我需要执行以下操作许多次:
a, b
a * b mod p
,其中p = 1000000007
和a, b
与p
的数量级相同我的直觉是天真的
result = a * b
result %= p
效率低下。我可以优化乘法模p
,就像使用p
优化取幂模pow(a, b, p)
一样吗?
答案 0 :(得分:11)
您提到“a, b
与p具有相同的数量级。”通常在加密中,这意味着a,b
是p
附近的大数字,但严格低于p
。
如果是这种情况,那么您可以使用简单身份
将您的计算转换为
result = ((a-p)*(b-p))%p
然后你将一个大的乘法转换成两个大的减法和一个小的乘法。你必须分析一下,看哪个更快。
答案 1 :(得分:6)
要在汇编中进行此计算,但是可以从Python调用它,我会 从a尝试inline assembly Python module written in C。 GCC和MSVC summary 编译器具有内联汇编功能,只有不同的语法。
请注意,我们的模数p = 1000000007
恰好适合30位。结果
在某些弱点的情况下,可以在Intel 80x86寄存器中计算所需的(a*b)%p
对a,b
的限制不比p
大。
对a,b
(1)a,b
是32位无符号整数
(2)a*b
小于p << 32
,即p
次2 ^ 32
特别是如果a,b
每个都小于2*p
,则会避免溢出。
给定(1),它们中的任何一个都小于p
就足够了。
Intel 80x86指令MUL可以乘以两个32位无符号整数 并将64位结果存储在累加器寄存器对EDX:EAX中。一些 有用的第10.2.1节讨论了MUL的细节和怪癖 {{3}}
指令DIV然后可以将该64位结果除以32位常数
(模数p
),将商存储在EAX中,余数存储在EDX中。
见最后一个链接的10.2.2节。我们想要的结果就是余数。
这种划分指令DIV应该存在溢出的风险 分子EDX中的64位乘积:EAX给出的商大于32位 不满足上述(2)。
我正在使用C / inline程序集中的代码片段来进行“概念验证”。
然而,速度的最大好处将取决于批处理数组
数据a,b
来处理,分摊函数调用的开销等
Python(如果那是目标平台)。
答案 2 :(得分:2)
这不能直接回答这个问题,但如果您正在寻找性能,我建议不要在纯Python中执行此操作。一些选择:
答案 3 :(得分:0)
虽然这非常简单,但您可以尝试使用基于mod p
构建产品列表,在1000000007
步骤上节省一些时间(列表的大小取决于{的大小{1}}和a
)。测试每个模数(从最高开始)。当然,这仅在b
时有用。
答案 4 :(得分:0)
如果您通过 许多 次澄清了您的意思,可能会有优化的线索,例如,如果您从高频循环中收集结果,循环可以提供优化常规的方法。
说未经优化的循环是:
p = 1000000007
b = 123456789
a = 0
while a < p:
result = (a * b) % p
dosomething(a, b, result)
a += 1
你可以优化高频循环中的*和%:
p = 1000000007
b = 123456789
a = 0
result = (a * b) % p
while a < p:
dosomething(a, b, result)
a += 1
result += b
if result >= p:
result -= p