几个大整数类乘法效率不完全比较[图表]

shines77 2004-07-22 11:00:48
比较的项目分为:

1。Big * Small 大数乘以小数,即一个大整数类 × 一个 UINT32 小整数;

2。位数等长的乘法,和不等长的乘法,由于不是每个整数类都提供随意初始化位数的接口,具体可以换为乘方来测试,可以表现出一个大整数类中等长度的乘法能力;

3。综合乘法效率,特别优化过的阶乘计算算法,一般都具有多样的乘法计算,在同一个算法下比较速度,考验综合的乘法能力。

由于不便贴图,图表和测试结果请看(待续中):

http://www.77studio.net/labs/intcmp.htm

并提供最新的测试包(07月22日最新,包含 HugeCalc v 3.0.0.1 beta 测试):

http://www.77studio.net/files/FactorialPack.rar
...全文
721 51 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
51 条回复
切换为时间正序
请发表友善的回复…
发表回复
gxqcn 2004-08-09
  • 打赏
  • 举报
回复
********************************
HugeCalc 已正式升级为 v3.0.0.1
********************************

----------------------------------------------------------------------------
n! | A B C | result
------------+---------------------------------+-----------------------------
10,000! | 0.031s 0.039s 0.031s | 0.28462... x 10^35,660
20,000! | 0.078s 0.089s 0.141s | 0.18192... x 10^77,338
40,000! | 0.203s 0.225s 0.406s | 0.20916... x 10^166,714
80,000! | 0.515s 0.721s 1.094s | 0.30977... x 10^357,507
100,000! | 0.625s 0.830s 1.422s | 0.28242... x 10^456,574
200,000! | 1.531s 2.118s 4.046s | 0.14202... x 10^973,351
400,000! | 3.782s 5.134s 10.016s | 0.25344... x 10^2,067,110
800,000! | 8.407s 11.411s 24.719s | 0.56846... x 10^4,375,040
1,000,000! | 12.687s 17.120s 44.219s | 0.82639... x 10^5,565,709
----------------------------------------------------------------------------

A -- HugeCalc 3.0.0.1
B -- apfloat 2.40
C -- Mathematica 4.0.0.0

----------------------------------------------------------------------------

备注:
1、以上测试均在同样的软硬件环境下:P4 CPU 1.70GHz / 256MRAM / WinXP;
2、以上测试均不含输出时间;
3、如果需要输出,Mathematica 将远落后于 HugeCalc 3.0.0.1!
4、前两者的阶乘算法采用了几乎同样的高效算法,Mathematica 则直接调用其内部函数;
5、第三方测试:http://www.77studio.net/labs/intcmp.htm

在此,特别感谢 shines(郭子) 提供的测试报告!
(正式版在原 beta 版上作了许多优化改进)

最新版下载地址::http://www.freewebs.com/maths/software.htm#02

因为我将迎接即将出生的儿子,所以本课题的研究将暂告一段落,
欢迎广大网友继续关注和探讨本课题,我也将会尽可能地参与讨论。
gxqcn 2004-07-28
  • 打赏
  • 举报
回复
你的建议,我可能在发布正式版时考虑进去。
yaos 2004-07-28
  • 打赏
  • 举报
回复
关于10的乘除法,完全可以独立的写函数。
不容易混淆

因为大数库,最好对外透明,完全看不出进制最好了
yaos 2004-07-28
  • 打赏
  • 举报
回复
以及“<<”、“<<=”、“>>”、“>>=”重定义为10进制的移位外,
(我认为其更符合人们的数学思维习惯)
------------------------------------
晕,这个不利于数学计算,而且没有任何意义

除了我将“^=”重定义为乘幂运算,
------------------------------
不好,^是逻辑运算 :)
不如用函数形式

gxqcn 2004-07-28
  • 打赏
  • 举报
回复
ClassT &ClassT::operator *=( const ClassT &right )
{
if ( &right == this )
return *this;

//...
}

怎么说不符合定义呢?

除了我将“^=”重定义为乘幂运算,
以及“<<”、“<<=”、“>>”、“>>=”重定义为10进制的移位外,
(我认为其更符合人们的数学思维习惯)
其它的运算符完全符合原本意义(上述改变,我在帮助中也特别作了说明)。

HugeCalc v3.0.0.1 的配套帮助也已全部更新,
至此,该版基本已定型,但公开发布日仍定于 2004-08-08,
主要是给大家和自己一个足够的缓冲时间。

to shines(郭子):
我已将最新的相关文件e-mail给你了,请注意查收。
yaos 2004-07-28
  • 打赏
  • 举报
回复
:)
不符合定义啊

建议重载的操作符严格符合C++的定义 :)
gxqcn 2004-07-28
  • 打赏
  • 举报
回复
"fact *= fact" 是直接返回 fact,因为在我的定义中,右边的操作数为常量,
所以,该现象不是bug,而是种保护。
shines77 2004-07-28
  • 打赏
  • 举报
回复
to gxqcn(GxQ):
我把我的阶乘程序里的“*”全部换成“*=”,把乘方的地方改了一下,使用你的dll速度就和你的HugeCalc 3.0.0.1 beta几乎一摸一样了,晕死,下载:

http://www.77studio.net/files/HugeCalc07-27.rar

另外,发现你的CHugeInt使用fact *= fact; 时计算结果错误,只能换成fact = fact ^ 2; 不知道算不算bug

to all:

全精度大整数阶乘快速算法[带源码]

http://community.csdn.net/Expert/topic/3216/3216727.xml?temp=.1520655

我先睡了,有时间我才来
shines77 2004-07-28
  • 打赏
  • 举报
回复
我看了一下VC的STL里的vector(其实我一直都没有用SGI-STL,我有,嫌麻烦懒得设置,呵呵,我知道VC的比它的慢),它用的也是new分配内存,但是可以用reserve()预先分配一些保留空间,就不必每次都new了

内存管理一般采用按Block的分配方式,易于回收和增长,一般都采取像yaos的4096 BYTE Block方式,这种方式就像FAT32里的簇大小一样(如果用链表在内存中实现类似FAT一样的方式,就不必把内存copy来copy去了,因为是不连续的内存地址,这样操作有些损耗,某些具体应用才考虑,扯远了);还有一种是保证大于目标长度的2倍最接近2的幂次方的值,如果目标长度是50,则分配128字节,如果长度达到65,则分配256字节。但是这样长度越大,可能浪费的内存就越多。

其实我不是专家,以上只是经验的瞎谈。

to liangbch(宝宝):
今天凌晨我一定把我的阶乘算法整理出来,我就是看了你的3.0部分源码,才有了公开代码的冲动,我想我应该做些什么(因为这些东西也不值钱,我也是网上找来的,花费了点时间去钻研而已,呵呵)

如果不周全之处,请先多包涵,有时间和精力以后我会做得更好的
liangbch 2004-07-27
  • 打赏
  • 举报
回复
郁闷!我的阶乘计算器在3.0版之后作了数次改动(每次改动都很大,但基本算法不变),包括优化乘法,本想在简化算法的基础上提高速度,但无一可达到3.0版的速度。

gxqcn 2004-07-27
  • 打赏
  • 举报
回复
测试代码:
BigInteger naiveFactorial(unsigned long n)
{
BigInteger f = 1;
for(unsigned long i=2; i<=n; i++)
{
f = f * (UINT32) i;
}
return f;
}


Simple Factorial Multiplication

P4 CPU 1.70GHz / 256MRAM / WinXP
================================
n! A B C D
2000! 0.015s 0.031s 0.03162245s 0.02587368s
4000! 0.078s 0.109s 0.11712634s 0.10492144s
6000! 0.203s 0.250s 0.26231099s 0.24322002s
8000! 0.375s 0.469s 0.46674899s 0.43868006s
10000! 0.609s 0.797s 0.73992812s 0.70184786s
16000! 1.671s 2.453s 2.20079340s 1.88741837s
20000! 2.719s 4.031s 4.00864747s 3.05229100s
40000! 11.797s 18.062s 18.01951812s 13.14591827s

A -- 自测程序(GDI),最新的 HugeCalc.dll,用 f *= (UINT32) i;
B -- 自测程序(GDI),最新的 HugeCalc.dll,用 f = f *(UINT32) i;
C -- FactorialPack,最新的 HugeCalc.dll;
D -- FactorialPack,GzFactorial.exe;

从上述数据表明,
1、应尽可能地调用“*=”运算符,它可减少拷贝构造过程。
2、如果测试“Big * Small”的能力,建议测试代码改成“f *= (UINT32) i;”形式;
3、奇怪的是 C 项比 B 项某些值会小一些,谁可以给我一个理由?
4、HugeCalc v3.0.0.1 在阶乘算法上与 v2.1.0.1 完全一致,我怀疑楼主测试时未调用到高效函数;
5、A 项数据已普遍优于 D 项数据 :)。

另外,GzFactorial.exe 在我家里的那台老爷机(Celeron 466MHz 64.0MB RAM/Win98Sec)无法运行,
我想是楼主调用了特殊的汇编所致。

HugeCalc v3.0.0.1 (beta) 刚进行过更新:
http://www.freewebs.com/maths/download/HugeCalc.rar(168 KB)
yaos 2004-07-27
  • 打赏
  • 举报
回复
Mul_Short??
提醒一下
STL的内存分配有点麻烦,效率不符合你的要求呢 :)

比如Array经过了包装,不如指针方便 :)

一般的计算类都自己做内存管理 :)

实现操作符重载的类函数真麻烦,涉及到内存拷来拷去,真不好玩,效率不如C高
需要优化的地方太多
gxqcn 2004-07-27
  • 打赏
  • 举报
回复
补充说明:
我的 Mul 算法分为:
Mul_Short
Mul_BaseCase
Mul_Karatsuba
Mul_FNT

至于GMP的TOOM,因为中间结果需除以3,所以不想去招惹麻烦。
前面说的关闭 FNT 算法,其实就是保留之前的 3 个算法。
gxqcn 2004-07-27
  • 打赏
  • 举报
回复
我的内存管理完全是“按需分配”,从不多开,
程序里基本没有“new / delete []”,我全部交给 STL 去管理,
至于它会不会开预留空间,我就不去细究了(也乐得清闲)。

apfloat 写得有点变态,:)
它的整数类居然是对浮点的包装(可能是为了对除法等算法的考虑吧)。
再有一点,它的代码我认为写得不规范,居然与 SGI-STL 不兼容,
我费了老大的劲才融入到我现有的工程中(许多地方干脆就是重写)。

对于 Big *= Small 这类运算,完全可以不必重开新空间,直接在原来的基础上计算更快!

shines(郭子),可得注意身体,身体可是革命的本钱啊!
(尽管我也是不会照顾我自己)。。。
yaos 2004-07-27
  • 打赏
  • 举报
回复
内存分配我采取的策略:
分配一个1024DWORD的空间,然后动态增长,增幅1024DWORD
shines77 2004-07-27
  • 打赏
  • 举报
回复
to gxqcn(GxQ):
1. 科学一点的说,"*="是比"*"快一些,但是由于apfloat每次都要重新分配内存(甚至进位的时候再重新分配一次,够晕了吧),我也知道这种做法的诟病,但是apfloat不怎么做好像有bug,还有一个原因是他重要面对小数(浮点小数)的计算,高位在前容易截尾(精度可限制),我的GzInteger也用了这个方法,本来最佳的方法是,分配一段比所要存储的空间稍大的内存,等数据变长的时候,可以不必重新分配内存,重新设置一下起始的指针就可以了,超过实际分配的内存的时候才重新分配,但是考虑到将来我可以把GzInteger的代码用到GzFloat(浮点小数类),我采用了apfloat的方法,野心很大,做起来就有点拖拉

2. 应该是这样科学一点,但对apfloat不太公平:),他应该重写一个整数类的,而不应该在apfloat上构建apint类

3. 可能是测量的误差吧,或者是GDI和Console的程序的区别,按理说是基本一样的

4. 我是按照用在apfloat的最快的参数计算的,也许连续Big*Small的长度可以调一调,会有改善,也许而已,有空我试试

5. B, D的 "*=" 和 "*" 效率是一样的,哭。。。。,有空我改改我的GzInteger

HugeCalc 3.0.0.1 出现的差距的问题我也在研究,也许是参数设置和某些函数的效率提高的问题,等我公布我的方法就真相大白了(我还在考虑,其实也没啥好考虑的,GzInteger加减法的部分都还没有写完,不过我可以先公开计算阶乘部分的代码)

我将 HugeCalc v3.0.0.1 中的 FNT 算法关闭,生成的 dll 放在 \FactorialPack\HugeCalc 3.0.0.1 beta 目录下运行,计算 400000!需要 24.409s;

原来用的是FNT 和 分治法配合使用的吗?关闭了是用分治法,还是硬乘法? 怎么会比“运行 \FactorialPack\HugeCalc 2.1.0.1\ 下的文件,计算 400000!需要 21.202s;”的还要慢啊,是不是新的代码跟原来的分治法有些地方有些小改动(为了加入和使用FNT)

最近几天可以帮朋友搞机器,还有我妹妹的电脑,可能没有空(身体也不太好,呵呵),有空我会继续努力的,晚上还有事,郁闷了,给他们搞一点酬劳都没有,没准别人还嫌我架子大呢(朋友要rm转VCD,他又不会ftp下载rm,又要装一个新硬盘,装系统(靠,玩电脑这么多年, 连个系统都不会装),服侍得服服帖帖,汗,这世道我迟早会累死的,最近身体极不好,帮老妹买了个摄像头,又要给她去装,承诺给她一个新硬盘,又得装系统,不过自己妹妹,这点辛苦是应该的,我拖了好久了,她在附近另外一个城市上班),以上纯属牢骚,权当作没看见,thanks
gxqcn 2004-07-27
  • 打赏
  • 举报
回复
to shines(郭子):

我将 HugeCalc v3.0.0.1 中的 FNT 算法关闭,生成的 dll 放在 \FactorialPack\HugeCalc 3.0.0.1 beta 目录下运行,计算 400000!需要 24.409s;

我自己的 HugeCalc.exe 调用它计算 400000!需要 19.953s;

运行 \FactorialPack\HugeCalc 2.1.0.1\ 下的文件,计算 400000!需要 21.202s;

从上可看出,我们的阶乘算法效率差距并不大,导致我们在测试 HugeCalc 3.0.0.1 出现较大的差距,并不是我的阶乘算法作过进一步的优化,而可能是与调用函数的效率高低相关。这也是我一直纳闷的地方。。。
yaos 2004-07-25
  • 打赏
  • 举报
回复
嘿,我也把我的96年的类拿出来,改写了 :)
名字叫Number,嘿

当时实现了全部5个运算 :),就是不是快算法
就是编译一次太麻烦,要30分钟
嗨,386sx/25,1M内存,BC31,哎
太痛苦了,因为最后实现四则运算出现问题放弃了
就是连续的
e = (a + b) * (c + d)
嘿,你们可以作作,麻烦
yaos 2004-07-25
  • 打赏
  • 举报
回复
Maple 9不要500M
因为我不知道到底多大,嘿嘿
没统计 :)
shines77 2004-07-25
  • 打赏
  • 举报
回复
为了测试方便 n ^ k, n是0到10^9-1的数, k是一个DWORD, 现在在外面, 好象是这样的吧

我并不是为测试乘幂, 最终是为了测试乘法的效率

阶乘不用比较了
GxQ的3.0.0.1最好了 :)

他的最新版的阶乘算法是比较快
加载更多回复(31)

33,027

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧