- 注册时间
- 2007-12-28
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 12787
- 在线时间
- 小时
|
发表于 2020-2-27 21:06:06
|
显示全部楼层
关于大数核心运算(对于应GMP的mpn目录下的底层函数)的进制。我仍然认为我的设计是最好的。
即32位下使用$2^30$进制,64位下使用$2^60$(其实单从大数乘法上看,$2^62$更好,但60的因数众多,更好拆分)进制。
非满进制格式的大数,存储开销稍大些,但可实现以列为主的乘法,可对双倍精度的乘积做多次累加而不溢出。
而满进制格式的大数,只能实现以行为主的大数乘法,无法充分利用SIMD指令的优势。
一个精心设计的乘法结构可充分利用SIMD的优势,加速大数运算的速度。
若每条指令的执行时间相当,则使用AVX512指令的$2^30$进制的大数乘法,极有可能比GMP64位的版本更快。
分析
一次64位×64位的乘法,等价于4次32位×32位的乘法. 故若4个32位×32位的乘法的实现快于一个64位×64位的乘法,则32位版本的乘法可快于64位乘法。
最近完成一个示范程序,核心是做s = sum( a[ i ] * b[ j ]),实现了4个版本,包括c语言版,sse2版, avx2版,avx512版, 计算4096对儿uint32乘法的积的累加,不考虑溢出,用时为6.3至0.25微秒。
|C版本|sse2|avx2|avx512|
|6.3us|0.92us|0.41us|0.25us|
下面比较一下各个版本的执行的指令数
对说32位C版本,典型的需要5条指令,大体是这个样子。
- mov eax, s1
- mov edx, s2
- mul edx
- add ecx, eax
- add ebx, edx
复制代码
而我写的SSE2版本,每4次uint32乘uint32需要9条指令,平均每次乘法需要2.25条指令
AVX2版本,每8次uint32乘uint32需要7条指令,平均每次乘法需要0.88条指令。
AVX512版本,每16次uint32乘uint32需要7条指令,平均每次乘法需要0.44条指令。
附以列为主的乘法和以行为主的乘法
1.以列为主的乘法
若被乘数是s1[], 其长度是len1, 乘数是s2[], 其长度是len2
该算法计算过程为,先固定k,则p[k]= sum(s1[ i ]*s2[k-i], 0<= i< len1, 0 <= k-i<len2).
2.以行为主的乘法
若被乘数是s1[], 其长度是len1, 乘数是s2[], 其长度是len2
计算过程为,先固定k,0<=k<len2, n=s2[k], 计算p[ i+k ]=sum(s1[ i ]*n,0<= i< len1)
|
|