本文系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 // FCBRUCEint 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 // FCBRUCEint 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 randomT_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; dopython data.py > inputpython std.py < input > std_outputbegin_time_int=$(date "+%s%N")./bign_int < input >bign_int_outputend_time_int=$(date "+%s%N") begin_time_longlong=$(date "+%s%N")./bign_longlong < input >bign_longlong_outputend_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;elseecho "Accepted"echo "run time : " $use_time_intfiechoecho "bign long long"diff std_output bign_longlong_output if [ $? -ne 0 ]; then echo "Wrong Answer"break;elseecho "Accepted"echo "run time : " $use_time_longlongfiechotest $use_time_longlong -lt $use_time_int if [ $? -ne 0 ] ; thenecho "int faster"elseecho "long long faster"fiechoechodone

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

参考资料:

《算法竞赛入门经典》—— 刘汝佳

探寻C/C++中更快的大数(自然数集)模板相关推荐

  1. 在Flutter中更快地加载您的图像资源

    本文主要介绍在Flutter中更快地加载您的图像资源 我们可以将图像放在我们的资产文件夹中,但如何更快地加载它们?这是 Flutter 中的一个秘密函数,可以帮助我们做到这一点 - precacheI ...

  2. idea中drl文件_得分DRL:在OptaPlanner中更快,更轻松

    idea中drl文件 对于OptaPlanner (= Drools Planner)6.0.0.Beta1,我已经用更优雅的ConstraintMatch系统替换了ConstraintOccurre ...

  3. linux中pushd和popd用法,使用Pushd和Popd命令在Linux中更快的导航目录

    本文介绍在Linux操作系统中更快的导航目录的方法:使用Pushd和Popd命令.我们通常使用cd /go/to/the/path来转到给定目录,使用cd ..返回一个父目录,并使用cd转到我们开始的 ...

  4. 分数DRL:在OptaPlanner中更快,更轻松

    对于OptaPlanner (= Drools Planner)6.0.0.Beta1,我已经用更优雅的ConstraintMatch系统替换了ConstraintOccurrence. 结果是您的D ...

  5. V8 中更快的异步函数和 promises

    原文作者:Maya Lekova and Benedikt Meurer 译者:UC 国际研发 Jothy 写在最前:欢迎你来到"UC国际技术"公众号,我们将为大家提供与客户端.服 ...

  6. 如何在职场中更快地成长

    hello,大家好,我是张张,「架构精进之路」公号作者. 最近,有个朋友跟我大吐苦水:"明明我已经工作这么多年了,为什么感觉还是在原地踏步没有成长?" 我很认真地跟他做了沟通,把几 ...

  7. append是什么意思java_为什么StringBuilder#append(int)在Java 7中比在Java 8中更快?

    在调查 little debate w.r.t.使用""和 Integer.toString(int)将整数原语转换为字符串我写了这个 JMH microbenchmark: @F ...

  8. quicksilver引擎_如何使用Quicksilver在macOS中更快地完成所有操作

    quicksilver引擎 () Your mouse is slowing you down. The less you use it, the faster you'll be able to d ...

  9. java 加载中_Java 6类加载中更快的是什么?

    小编典典 Java 6编译器将预验证信息添加到类文件中 如果Java虚拟机实现曾经尝试对50.0版类文件执行通过类型推断的验证,则在通过类型检查的验证失败的所有情况下都必须这样做. 这意味着Java虚 ...

最新文章

  1. centos 安装 mysql 5.7
  2. 合成(composite)模式
  3. linux 从行查看文件,linux 查看文件内容
  4. python读取.set文件
  5. UVA, 580 Critical Mass
  6. Linux中 set、env、declare、export显示shell变量的区别
  7. web页面锁屏初级尝试
  8. 边缘计算与云计算的不同,这篇说明白了!
  9. CSS3实现卡片翻转动画
  10. 纪念贴:历史会证明今天是不是开创新历史的一天
  11. 【拯救赵明】网页防篡改攻略
  12. STM8S103f单片机的开发(1)LED灯的点亮
  13. 2019年2月10日训练日记
  14. [ActiveForm] -- ActiveForm::begin表单用法
  15. 如何开启QQ在线客服
  16. RocketMQ广播消费与集群消费
  17. kali攻击wifi、破解wifi详细教程(仅供学习使用)
  18. 万年历的Java代码
  19. RGB图像卷积生成Feature map特征图过程
  20. php.ini中文翻译版--转载

热门文章

  1. ubuntu 18,问题总结
  2. 搞了一个论坛玩玩!http://lupeiqing.3322.org/bbs
  3. TortoiseSVN 设置中文语言包
  4. 云队友丨跳槽?还是跳坑??
  5. 使用Dreamweaver MX制作基础简易6行8列个人简历表格。
  6. java夯实基础系列:反射
  7. Spring框架的ImportSelector到底可以干嘛
  8. 2019最新全套JAVA全套课程
  9. 红米note5解锁教程_红米Note5解锁bl教程_红米Note5获取解锁码进行一键解锁的方法...
  10. linux定时任务输出时间日志,linux 定时任务 日志记录