This ruby file produces correct results for the 2 functions.
modinvtest.rb
def modinv(a0, m0)
return 1 if m0 == 1
a, m = a0, m0
x0, inv = 0, 1
while a > 1
inv -= (a / m) * x0
a, m = m, a % m
x0, inv = inv, x0
end
inv += m0 if inv < 0
inv
end
def modinv1(r, m)
inv = r
while (r * inv) % m != 1; inv *= r end
inv % m
end
def tm; t = Time.now; yield; Time.now - t end
resp7 = [11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,
97,101,103,107,109,113,121,127,131,137,139,143,149,151,157,163,
167,169,173,179,181,187,191,193,197,199,209,211]
print resp7.map { |r| modinv(r, 210) }
puts
print resp7.map { |r| modinv1(r, 210) }
puts
puts tm{ 100000.times {resp7.each { |r| modinv(r, 210) } } }
puts tm{ 100000.times {resp7.each { |r| modinv1(r, 210) } } }
For the equivalent Crystal code, the 2nd version – modinv1
– produces incorrect results for multiple inputs, and if I don’t use &*
it gives arithmetic overflow errors.
These number are so small these errors make no sense at all.
modinvtest.cr
def modinv(a0, m0)
return 1 if m0 == 1
a, m = a0, m0
x0, inv = 0, 1
while a > 1
inv -= (a // m) * x0
a, m = m, a % m
x0, inv = inv, x0
end
inv += m0 if inv < 0
inv
end
def modinv1(r, m)
r = inv = r.to_u64
while (r &* inv) % m != 1; inv &*= r end
inv % m
end
def tm; t = Time.monotonic; yield; Time.monotonic - t end
resp7 = [11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,
97,101,103,107,109,113,121,127,131,137,139,143,149,151,157,163,
167,169,173,179,181,187,191,193,197,199,209,211]
puts resp7.map { |r| modinv(r, 210) }
puts resp7.map { |r| modinv1(r, 210) }
puts tm{ 100000.times {resp7.each { |r| modinv(r, 210) } } }
puts tm{ 100000.times {resp7.each { |r| modinv1(r, 210) } } }