私は非常に集中的に使用しなければならないpowMod
関数を書いています。累乗剰余演算関数の整数オーバーフロー
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
:出発点は、カスタム
pow
関数である。出力を表現するのに十分な大きさと私は
bigint
で高価な計算を避けることができるので、
// 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
を選びました
モジュロ(m
)が乗数(a
,b
)よりも大きく、関数が負でない数値だけで動作すると仮定します。 ほとんどの場合、powMod
の機能は正しいです。ただし、a*b
がint64
の範囲を超えている可能性がありますが、(a*b)%m
はではないmulMod
機能に問題があります。たとえば、以下の ザ・オーバーフローの問題を示しています
let a = (pown 2L 40) - 1L
let b = (pown 2L 32) - 1L
let p = powMod a b 2 // p = -8589934591L -- wrong
はbigint
タイプに頼ることなくint64
オーバーフローを回避するための方法はありますか?
乗算を行う前に、それぞれを個別にモジュロ化する方法を見つけようとしますか?または、それはうまくいかないかもしれませんが、共通の除数で分けることができれば、それを乗算することができます。残念ながら、あなたが行うことはパフォーマンスに影響を与えます。 –
それは役に立ちません。私はすでに乗数がモジュロよりも小さいと仮定しています。 – pad
かなり精度の高いdecimalを使うことができますが、bigintよりも少し速いです:| –