使用Miller Rabin算法找素数

我使用Lua实现了Miller-Rabin算法,并试图得到一致的素数返回。但这个实现只有一半的时间可以工作。尽管如果我在Python中实现类似的代码,那样代码100%可以工作。有没有人能指点我正确的方向呢?

--分解n-1为 (2^s)*d
local function decompose(negOne)
  exponent, remainder = 0, negOne
  while (remainder%2) == 0 do
    exponent = exponent+1
    remainder = remainder/2
  end
  assert((2^exponent)*remainder == negOne and ((remainder%2) == 1), "设置s和d的值时出现错误")
  return exponent, remainder
end

local function isNotWitness(n, possibleWitness, exponent, remainder)
  witness = (possibleWitness^remainder)%n

  if (witness == 1) or (witness == n-1) then
    return false
  end

  for _=0, exponent do
    witness = (witness^2)%n
    if witness == (n-1) then
      return false
    end
  end

  return true
end

--使用miller-rabin素性测试
--n是要测试的整数,k是测试的准确度
local function isProbablyPrime(n, accuracy)
  if n <= 3 then
    return n == 2 or n == 3
  end
  if (n%2) == 0 then
    return false
  end

  exponent, remainder = decompose(n-1)

  --检查是否为合数
  for i=0, accuracy do
    math.randomseed(os.time())
    witness = math.random(2, n - 2)
    if isNotWitness(n, witness, exponent, remainder) then
      return false
    end
  end

  --可能是素数
  return true
end

if isProbablyPrime(31, 30) then
  print("是素数")
else
  print("不是")
end
点赞
用户1847592
用户1847592

Python 可以支持任意长度的整数。但 Lua 不支持。

问题出在 witness = (possibleWitness^remainder)%n 上。

Lua 无法直接计算出 29^15 % 31 的精确结果。

但我们可以使用下面这个小技巧来计算小于 sqrt(2^53) 的数字:

witness = mulmod(possibleWitness, remainder, n)

其中

local function mulmod(a, e, m)
   local result = 1
   while e > 0 do
      if e % 2 == 1 then
         result = result * a % m
         e = e - 1
      end
      e = e / 2
      a = a * a % m
   end
   return result
end
2018-05-27 05:10:42