2024.10.16 鲜花

PRAGMATISM -RESURRECTION

凭什么没词就不是好歌!!!

取模优化

就不讲怎么减少取模了。

比较广为流传的有两种,Barrett reduction,Montgomery Algorithm。

对于固定常数模数,计算机已经优化的很好了,一般不会有太大效果(确实有,用 Barrett reduction 有时可以卡常)。

对于输入的固定模数(即不会改变),可以用一下算法优化。

Barrett reduction:

一句话总结,比较有用,比较好写

考虑对于 amodm,可以用 amam,但是直接计算 am,由于除法的常数,并不会快。

众所周知,不能精确计算的就粗略计算,考虑除以 2k 是快的,因为可以用位运算,于是我们考虑将 am 用除以 2k 估算。

具体的,设 base=2km,于是 am 可以粗略计算为 basea2k

优点是简洁好写,缺点是有一定错误率,且需要用 __int128

错误率:显然,basea2kam 对于 k64 时,m109 左右的模数,极限值域在 1018 时,用 __uint128_t 存储 base,在测试了 1010 组纯随机数据中,ambasea2k1,可以加上判断来减掉误差(虽然会变慢)。

Montgomery Algorithm:

一句话总结,卵用没有。

考虑对于加减法,显然可以用判断来代替取模,对于乘法(abmodm),我们考虑优化。

这里我们需要 m2

R=2k>m,a=aRmodm,b=bRmodm

显然有 abRabR1(modm),aR1aR2(modm),bR1bR2(modm),而 R2modm 是可以预处理的,所以我们只要能够快速求出 xR1modm 就可以快速求出 a,b,进而求出 abR,ab

如何求出 xR1 ,考虑求最小的 k 满足 R|x+km,在将 R 除掉即可,k(mod)xm1(modR),提前处理 m1modR即可。

优点是不用 __int128,并且实现精细的话可能更快,缺点是必须精细实现,要封装 modint 来减少转换,细节较多(反正我调了一下午还不如本地动态模数暴力快,提交比固定模数略慢)。

唯一的作用没准就是做模板题 at_arc148_f

速度测试以后会补,有简单的本地评价: Barrett reduction 未加判断。

固定模数: =Barrettreduction<MontgomeryAlgorithm

非固定数: Barrettreduction<<MontgomeryAlgorithm

学校 OJ 上固定模数 Montgomery Algorithm 略慢于默认,Barrett reduction 略快于默认。

Barrett reduction,Montgomery Algorithm 都不会受模数是否固定影响。

Upd:
给一个板子:

Mbs = (__int128(1) << 64) / MOD; // init
int Mod(int x){
return (x -= ((__int128(x) * m) >> 64) * MOD) >= MOD ? x - MOD : x;
}
P


posted @   5k_sync_closer  阅读(64)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示