探索C/C++大数快(自然数)模板

时间:2023-01-14 10:13:52

本文fcbruce个人原创整理。转载请注明出处http://blog.csdn.net/u012965890/article/details/40432511,谢谢。

我们知道在C/C++中int型可处理-2^31~2^31-1(32位及以上编译器),long long型可处理-2^63~2^63-1的数据,这实际上是非常有限的。在非常多情况下。我们往往会处理范围更大的数据。

Java中有BigInteger类,python中想要多大就有多大(取决于内存),可是C/C++就显得有些乏力,这时候我们会手写大数类。用一个数组记录一个数,来模拟竖式计算。

通常我们会一位一位地储存数据,这样易于实现,逻辑清晰,方便理解,可是一定程度上牺牲了效率,浪费了资源,那么是否能多位存储数据并操作呢。显然是能够的。

我们知道int类型能表示的最大数量级为10^9左右,为了避免乘法溢出,我们最好还是用一个int存储4位数字(10^4),能够轻易写下例如以下代码(仅含加、减、乘和比較操作):

/*
*
* Author : fcbruce <fcbruce8964@gmail.com>
*
* Time : Fri 24 Oct 2014 02:43:41 PM CST
*
*/
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10 #ifdef _WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif #define maxm
#define maxn using namespace std; const int maxl = 233;
struct bign
{
static int width;
static int mod;
int len,s[maxl]; bign()
{
memset(s,0,sizeof s);
len=1;
} bign(int num)
{
*this=num;
} bign(long long num)
{
*this=num;
} bign(const char *s)
{
*this=s;
} bign operator = (int num)
{
char s[maxl];
sprintf(s,"%d",num);
*this=s;
return *this;
} bign operator = (long long num)
{
char s[maxl];
sprintf(s,lld,num);
*this=s;
return *this;
} bign operator = (const char *s)
{
int l=strlen(s);
len=0;
for (int i=l-1;i>=0;i-=width,len++)
{
(*this).s[len]=0;
for (int j=max(0,i-width+1);j<=i;j++)
(*this).s[len]=(*this).s[len]*10+s[j]-'0';
} return *this;
} void str(char *s)
{
char format[5];
sprintf(format,"%%0%dd",width);
for (int i=len-1,j=0;i>=0;i--,j++)
sprintf(s+j*width,format,(*this).s[i]); int j=0;
while (s[j]=='0' && s[j+1]!='\0') j++;
strcpy(s,s+j);
} bign operator + (const bign &b)const
{
bign c;
c.len=0;
for (int i=0,g=0;g || i<max(len,b.len);i++)
{
int x=g;
if (i<len) x+=s[i];
if (i<b.len) x+=b.s[i];
c.s[c.len++]=x%mod;
g=x/mod;
} return c;
} void clean()
{
while (len>1 && s[len-1]==0) len--;
} bign operator * (const bign &b)
{
bign c;c.len=len+b.len;
for (int i=0;i<len;i++)
for (int j=0;j<b.len;j++)
c.s[i+j] += s[i] * b.s[j];
for (int i=0;i<c.len-1;i++)
{
c.s[i+1]+=c.s[i]/mod;
c.s[i]%=mod;
} c.clean();
return c;
} bign operator - (const bign &b)
{
bign c;c.len=0;
for (int i=0,g=0;i<len;i++)
{
int x=s[i]-g;
if (i<b.len) x-=b.s[i];
if (x>=0) g=0;
else
{
g=1;
x+=mod;
}
c.s[c.len++]=x;
} c.clean();
return c;
} bool operator < (const bign &b)const
{
if (len!=b.len) return len<b.len;
for (int i=len-1;i>=0;i--)
if (s[i]!=b.s[i]) return s[i]<b.s[i];
return false;
} bool operator > (const bign &b)const
{
return b<*this;
} bool operator <= (const bign &b)const
{
return !(b>*this);
} bool operator >= (const bign &b)const
{
return !(b<*this);
} bool operator == (const bign &b)const
{
if (len!=b.len) return false;
for (int i=0;i<len;i++)
if (s[i]!=b.s[i]) return false;
return true;
} bign operator += (const bign &b)
{
*this=*this+b;
return *this;
}
}; int bign::width=4;
int bign::mod=10000; int main()
{
#ifdef FCBRUCE
// freopen("/home/fcbruce/code/t","r",stdin);
#endif // FCBRUCE int T_T;
scanf("%d",&T_T);
bign a,b,c;
char s1[233],s2[233],s[233]; while (T_T--)
{
scanf("%s %s",s1,s2);
a=s1;b=s2;
c=a+b;
c.str(s);
printf("%s ",s); c=a-b;
c.str(s);
printf("%s ",s); c=a*b;
c.str(s);
printf("%s\n",s);
} return 0;
}

当中void str(char *)函数为将该大数转换成字符串。

随机生成100000组10^82数量级下面的数据并进行对拍,没有发现错误。

long long能表示的数据范围更大,能压很多其它的位数。会不会更快呢?最好还是一次压8位。对以上代码稍加修改就可以

/*
*
* Author : fcbruce <fcbruce8964@gmail.com>
*
* Time : Fri 24 Oct 2014 02:43:41 PM CST
*
*/
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10 #ifdef _WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif #define maxm
#define maxn using namespace std; const int maxl = 233;
struct bign
{
static int width;
static long long mod;
int len;
long long s[maxl]; bign()
{
memset(s,0,sizeof s);
len=1;
} bign(int num)
{
*this=num;
} bign(long long num)
{
*this=num;
} bign(const char *s)
{
*this=s;
} bign operator = (int num)
{
char s[maxl];
sprintf(s,"%d",num);
*this=s;
return *this;
} bign operator = (long long num)
{
char s[maxl];
sprintf(s,lld,num);
*this=s;
return *this;
} bign operator = (const char *s)
{
int l=strlen(s);
len=0;
for (int i=l-1;i>=0;i-=width,len++)
{
(*this).s[len]=0;
for (int j=max(0,i-width+1);j<=i;j++)
(*this).s[len]=(*this).s[len]*10+s[j]-'0';
} return *this;
} void str(char *s)
{
char format[10];
sprintf(format,"%%0%d%s",width,lld+1);
for (int i=len-1,j=0;i>=0;i--,j++)
sprintf(s+j*width,format,(*this).s[i]); int j=0;
while (s[j]=='0' && s[j+1]!='\0') j++;
strcpy(s,s+j);
} bign operator + (const bign &b)const
{
bign c;
c.len=0;
long long g=0ll;
for (int i=0;g!=0ll || i<max(len,b.len);i++)
{
long long x=g;
if (i<len) x+=s[i];
if (i<b.len) x+=b.s[i];
c.s[c.len++]=x%mod;
g=x/mod;
} return c;
} void clean()
{
while (len>1 && s[len-1]==0) len--;
} bign operator * (const bign &b)
{
bign c;c.len=len+b.len;
for (int i=0;i<len;i++)
for (int j=0;j<b.len;j++)
c.s[i+j] += s[i] * b.s[j];
for (int i=0;i<c.len-1;i++)
{
c.s[i+1]+=c.s[i]/mod;
c.s[i]%=mod;
} c.clean();
return c;
} bign operator - (const bign &b)
{
bign c;c.len=0;
long long g=0ll;
for (int i=0;i<len;i++)
{
long long x=s[i]-g;
if (i<b.len) x-=b.s[i];
if (x>=0) g=0;
else
{
g=1;
x+=mod;
}
c.s[c.len++]=x;
} c.clean();
return c;
} bool operator < (const bign &b)const
{
if (len!=b.len) return len<b.len;
for (int i=len-1;i>=0;i--)
if (s[i]!=b.s[i]) return s[i]<b.s[i];
return false;
} bool operator > (const bign &b)const
{
return b<*this;
} bool operator <= (const bign &b)const
{
return !(b>*this);
} bool operator >= (const bign &b)const
{
return !(b<*this);
} bool operator == (const bign &b)const
{
if (len!=b.len) return false;
for (int i=0;i<len;i++)
if (s[i]!=b.s[i]) return false;
return true;
} bign operator += (const bign &b)
{
*this=*this+b;
return *this;
}
}; int bign::width=8;
long long bign::mod=100000000ll; int main()
{
#ifdef FCBRUCE
// freopen("/home/fcbruce/code/t","r",stdin);
#endif // FCBRUCE int T_T;
scanf("%d",&T_T);
bign a,b,c;
char s1[233],s2[233],s[233]; while (T_T--)
{
scanf("%s %s",s1,s2);
a=s1;b=s2;
c=a+b;
c.str(s);
printf("%s ",s); c=a-b;
c.str(s);
printf("%s ",s); c=a*b;
c.str(s);
printf("%s\n",s);
} return 0;
}

改动对拍代码。发现使用压8位的long long 版大数从性能上确实要优于压4位的int版大数,尽管int版偶尔会稍快于long long版,但平均性能上long long版要比int版快20%~60%(包含IO)

数据生成代码:

#
#
# Author : fcbruce <fcbruce8964@gmail.com>
#
# Time : Fri 24 Oct 2014 06:33:17 PM CST
#
# import random T_T=100000
print T_T
for i in xrange(T_T):
a=random.randint(0,1237648236422345678987655432349875934875632123131523784682932317237132418743972317);
b=random.randint(0,12345678987623463824593658235543232123131238746239523172371376382423749824172324317);
print a+b,a

标程代码:

#
#
# Author : fcbruce <fcbruce8964@gmail.com>
#
# Time : Fri 24 Oct 2014 06:38:52 PM CST
#
# n=input() for i in xrange(n):
a,b=map(int,raw_input().split())
print a+b,a-b,a*b

对拍代码:

#!/bin/bash
#
# Author : fcbruce <fcbruce8964@gmail.com>
#
# Time : Fri 24 Oct 2014 07:01:27 PM CST
#
#
while true; do
python data.py > input
python std.py < input > std_output begin_time_int=$(date "+%s%N")
./bign_int < input >bign_int_output
end_time_int=$(date "+%s%N") begin_time_longlong=$(date "+%s%N")
./bign_longlong < input >bign_longlong_output
end_time_longlong=$(date "+%s%N") use_time_int=$(expr $end_time_int - $begin_time_int)
use_time_longlong=$(expr $end_time_longlong - $begin_time_longlong) echo "bign int"
diff std_output bign_int_output
if [ $? -ne 0 ]; then
echo "Wrong Answer"
break;
else
echo "Accepted"
echo "run time : " $use_time_int
fi echo echo "bign long long"
diff std_output bign_longlong_output
if [ $? -ne 0 ]; then
echo "Wrong Answer"
break;
else
echo "Accepted"
echo "run time : " $use_time_longlong
fi echo test $use_time_longlong -lt $use_time_int
if [ $? -ne 0 ] ; then
echo "int faster"
else
echo "long long faster"
fi echo
echo done

部分測试结果(执行时间单位:十亿分之中的一个秒,測试环境:ubuntu10.04 ,编译开O2优化。gnu++0x。主频:2.26GHz × 2 ):

探索C/C++大数快(自然数)模板

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjk2NTg5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

参考资料:

《算法入门经典大赛》—— 刘如家

探索C/C++大数快(自然数)模板的更多相关文章

  1. hdu 1425&colon;sort(排序,经典题。快排模板)

    sort Time Limit : 6000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submissi ...

  2. 快读&amp&semi;快写模板【附O2优化】

    快读&快写模板 快读快写,顾名思义,就是提升输入和输出的速度.在这里简单介绍一下几种输入输出的优劣. C++ cin/cout 输入输出:优点是读入的时候不用管数据类型,也就是说不用背scan ...

  3. poj 1811 随机素数和大数分解(模板)

    Sample Input 2 5 10 Sample Output Prime 2 模板学习: 判断是否是素数,数据很大,所以用miller,不是的话再用pollard rho分解 miller : ...

  4. Java 大数、高精度模板

    介绍: java中用于操作大数的类主要有两个,一个是BigInteger,代表大整数类用于对大整数进行操作,另一个是BigDecimal,代表高精度类,用于对比较大或精度比较高的浮点型数据进行操作.因 ...

  5. C&plus;&plus;快读模板

    C++的快速读入模板 inline int read() { ; char ch = getchar(); ') { if (ch == '-') flag = true; ch = getchar( ...

  6. &lbrack;hdu1402&rsqb;大数乘法&lpar;FFT模板&rpar;

    题意:大数乘法 思路:FFT模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ...

  7. 快读模板 &plus; &num;define 压缩for

    快读是一个很重要的模板 #define 压缩for是为了代码的简洁 这里贴一下模板 #define f(i , a , b) for(int i=(a) ; i <= (b) ; i++) us ...

  8. c&plus;&plus;快读与快输模板

    快读 inline int read() { ; ; char ch=getchar(); ; ch=getchar();} )+(X<<)+ch-'; ch=getchar();} if ...

  9. c&plus;&plus; 快读快输模板

    快读 inline int read() { ; ; char ch=getchar(); ; ch=getchar();} )+(X<<)+ch-'; ch=getchar();} if ...

随机推荐

  1. 【转】PHP中获取当前系统时间、时间戳

    今天写下otime($time, $now)为将时间格式转为时间戳,$time为必填.清楚了这个,想了解更多,请继续往下看. 3. date($format)用法比如:echo date('Y-m-d ...

  2. Excel表格解析

    //add by yangwenpei WGCW-144 使用Excel表格导入纸票记录 20161212 start /** * @param fileInputStream * @param co ...

  3. paip&period;为什么使用多线程的原因&period;

    paip.为什么使用多线程的原因. 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn.net/att ...

  4. 多个ajax请求下等待条显示和隐藏的简单处理

    处理为遇到ajax请求就显示等待条,直到所有的ajax请求执行完毕才关闭等待条.比较简单,源码如下(基于jQuery) //基于jQuery //从第一个ajax请求发出开始显示等待条?直到一系列aj ...

  5. IOS开发UI基础之Plis文件-字典转模型

    什么是plist文件? 在开发中直接将数据写在代码里面 不是一种合理的做法 如果数据经常改变 就需要经常翻开对应的代码进行修改 造成代码扩展性低 因此,可以考虑将经常变的数据放在⽂文件中进⾏行存储,程 ...

  6. poj3678&lpar;two-sat&rpar;

    传送门:Katu Puzzl 题意:n个点,点的取值可以是0或者1.m条边,有权值,有运算方式(并,或,异或),要求和这条边相连的两个点经过边上的运算后的结果是边的权值.问你有没有可能把每个点赋值满足 ...

  7. androidStudio 中 gradle 常用功能

    1. gradle 使用 svn 当前版本信息. def getSvnRevision() { new ByteArrayOutputStream().withStream { os -> de ...

  8. http进阶

    前言: 上一篇博文已经说到了,apache2.4简单的配置,端口,持久连接,MPM,DSO,路径下基于来源控制,页面特性,日志设置 安全域,虚拟主机等等. 一:URL URL是互联中获取标记资源的方式 ...

  9. EF Code First 连接MySql

    看了很多文章,尝试了很多次总是进行不下去,整理一下,以便日后查看. 1.创建ASP.NET MVC项目(EFCodeFirst) 1.1.右键点击引用选择管理NuGet程序包下载MySql.Data. ...

  10. poj 3683&lpar;2-SAT&plus;SCC&rpar;

    传送门:Problem 3683 https://www.cnblogs.com/violet-acmer/p/9769406.html 参考资料: [1]:挑战程序设计竞赛 题意: 有n场婚礼,每场 ...