探寻C/C++中更快的大数(自然数集)模板
本文系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++中更快的大数(自然数集)模板相关推荐
- 在Flutter中更快地加载您的图像资源
本文主要介绍在Flutter中更快地加载您的图像资源 我们可以将图像放在我们的资产文件夹中,但如何更快地加载它们?这是 Flutter 中的一个秘密函数,可以帮助我们做到这一点 - precacheI ...
- idea中drl文件_得分DRL:在OptaPlanner中更快,更轻松
idea中drl文件 对于OptaPlanner (= Drools Planner)6.0.0.Beta1,我已经用更优雅的ConstraintMatch系统替换了ConstraintOccurre ...
- linux中pushd和popd用法,使用Pushd和Popd命令在Linux中更快的导航目录
本文介绍在Linux操作系统中更快的导航目录的方法:使用Pushd和Popd命令.我们通常使用cd /go/to/the/path来转到给定目录,使用cd ..返回一个父目录,并使用cd转到我们开始的 ...
- 分数DRL:在OptaPlanner中更快,更轻松
对于OptaPlanner (= Drools Planner)6.0.0.Beta1,我已经用更优雅的ConstraintMatch系统替换了ConstraintOccurrence. 结果是您的D ...
- V8 中更快的异步函数和 promises
原文作者:Maya Lekova and Benedikt Meurer 译者:UC 国际研发 Jothy 写在最前:欢迎你来到"UC国际技术"公众号,我们将为大家提供与客户端.服 ...
- 如何在职场中更快地成长
hello,大家好,我是张张,「架构精进之路」公号作者. 最近,有个朋友跟我大吐苦水:"明明我已经工作这么多年了,为什么感觉还是在原地踏步没有成长?" 我很认真地跟他做了沟通,把几 ...
- append是什么意思java_为什么StringBuilder#append(int)在Java 7中比在Java 8中更快?
在调查 little debate w.r.t.使用""和 Integer.toString(int)将整数原语转换为字符串我写了这个 JMH microbenchmark: @F ...
- quicksilver引擎_如何使用Quicksilver在macOS中更快地完成所有操作
quicksilver引擎 () Your mouse is slowing you down. The less you use it, the faster you'll be able to d ...
- java 加载中_Java 6类加载中更快的是什么?
小编典典 Java 6编译器将预验证信息添加到类文件中 如果Java虚拟机实现曾经尝试对50.0版类文件执行通过类型推断的验证,则在通过类型检查的验证失败的所有情况下都必须这样做. 这意味着Java虚 ...
最新文章
- centos 安装 mysql 5.7
- 合成(composite)模式
- linux 从行查看文件,linux 查看文件内容
- python读取.set文件
- UVA, 580 Critical Mass
- Linux中 set、env、declare、export显示shell变量的区别
- web页面锁屏初级尝试
- 边缘计算与云计算的不同,这篇说明白了!
- CSS3实现卡片翻转动画
- 纪念贴:历史会证明今天是不是开创新历史的一天
- 【拯救赵明】网页防篡改攻略
- STM8S103f单片机的开发(1)LED灯的点亮
- 2019年2月10日训练日记
- [ActiveForm] -- ActiveForm::begin表单用法
- 如何开启QQ在线客服
- RocketMQ广播消费与集群消费
- kali攻击wifi、破解wifi详细教程(仅供学习使用)
- 万年历的Java代码
- RGB图像卷积生成Feature map特征图过程
- php.ini中文翻译版--转载
热门文章
- ubuntu 18,问题总结
- 搞了一个论坛玩玩!http://lupeiqing.3322.org/bbs
- TortoiseSVN 设置中文语言包
- 云队友丨跳槽?还是跳坑??
- 使用Dreamweaver MX制作基础简易6行8列个人简历表格。
- java夯实基础系列:反射
- Spring框架的ImportSelector到底可以干嘛
- 2019最新全套JAVA全套课程
- 红米note5解锁教程_红米Note5解锁bl教程_红米Note5获取解锁码进行一键解锁的方法...
- linux定时任务输出时间日志,linux 定时任务 日志记录