我正在写一个powMod
函数,我必须使用相当密集的函数。其出发点是一个自定义pow
功能:模数求幂函数中的整数溢出
// Compute power using multiplication and square.
// pow (*) (^2) 1 x n = x^n
let pow mul sq one x n =
let rec loop x' n' acc =
match n' with
| 0 -> acc
| _ -> let q = n'/2
let r = n'%2
let x2 = sq x'
if r = 0 then
loop x2 q acc
else
loop x2 q (mul x' acc)
loop x n one
检查我的输入范围后,我选择了int64
因为它足够大代表输出和我能避免昂贵的计算与bigint
:
let mulMod m a b = (a*b)%m
let squareMod m a = mulMod m a a
let powMod m = pow (mulMod m) (squareMod m) 1L
我假设模数(m
)大于乘数(a
,b
),函数仅适用于非负数。 对于大多数情况,powMod
函数是正确的;然而,问题在于mulMod
函数,其中a*b
可能超过int64
范围,但(a*b)%m
不是。 下面的例子演示了溢出问题:
let a = (pown 2L 40) - 1L
let b = (pown 2L 32) - 1L
let p = powMod a b 2 // p = -8589934591L -- wrong
有什么办法避免int64
溢出而不诉诸bigint
类型?
尝试找到一种方法来做每个单独的模块之前做乘法吗?或者,这可能行不通,但如果你可以用一个公约数分开,那么你就可以做到这一点。不幸的是,你所做的任何事都会影响性能 – 2012-01-02 21:33:26
它没有帮助。我已经假定乘数小于模数。 – pad 2012-01-02 21:52:48
您可以使用精度相当高的小数,但它只比bigint稍微快一些:| – 2012-01-03 18:32:36