R-Lehmann原始性测试中的模数警告

时间:2011-12-20 19:15:05

标签: r primes

我花了一点时间来攻击lehmann素性测试的R实现。我从http://davidkendal.net/articles/2011/12/lehmann-primality-test

借来的功能设计

这是我的代码:

primeTest <- function(n, iter){
  a <- sample(1:(n-1), 1)
    lehmannTest <- function(y, tries){
    x <- ((y^((n-1)/2)) %% n)
    if (tries == 0) {
      return(TRUE)
            }else{          
      if ((x == 1) | (x == (-1 %% n))){
        lehmannTest(sample(1:(n-1), 1), (tries-1))
      }else{
    return(FALSE)
      }
    }
  }
  lehmannTest(a, iter)
}

primeTest(4, 50) # false
primeTest(3, 50) # true
primeTest(10, 50)# false
primeTest(97, 50) # gives false # SHOULD BE TRUE !!!! WTF

prime_test<-c(2,3,5,7,11,13,17 ,19,23,29,31,37)

for (i in 1:length(prime_test)) {
  print(primeTest(prime_test[i], 50))
}

对于小素数它可以工作,但是当我到达~30时,我得到一个看起来很糟糕的消息,并且该功能停止正常工作:

2: In lehmannTest(a, iter) : probable complete loss of accuracy in modulus

经过一番调查后,我认为它与浮点转换有关。非常大的数字是四舍五入的,因此mod函数给出了错误的响应。

现在问题。

  1. 这是浮点问题吗?还是在我的实施中?
  2. 是否有一个纯粹的R解决方案或者R只是坏了吗?
  3. 由于

    解决方案:

    在有关模幂运算算法的大量反馈和一小时阅读后,我有一个解决方案。首先是制作我自己的模幂运算函数。基本思想是模块化乘法允许您计算中间结果。你可以在每次迭代后计算mod,因此永远不会得到一个巨大的令人讨厌的数字,它会淹没16位的R int。

    modexp<-function(a, b, n){
        r = 1
        for (i in 1:b){
            r = (r*a) %% n
        }
        return(r)
    }
    
    
    primeTest <- function(n, iter){
       a <- sample(1:(n-1), 1)
        lehmannTest <- function(y, tries){
          x <- modexp(y, (n-1)/2, n)   
        if (tries == 0) {
          return(TRUE)
                }else{          
          if ((x == 1) | (x == (-1 %% n))){
            lehmannTest(sample(1:(n-1), 1), (tries-1))
            }else{
            return(FALSE)
             }
        }
      }
       if( n < 2 ){
         return(FALSE)
         }else if (n ==2) {
           return(TRUE)
           } else{
             lehmannTest(a, iter)
             }
    }
    
    primeTest(4, 50) # false
    primeTest(3, 50) # true
    primeTest(10, 50)# false
    primeTest(97, 50) # NOW IS TRUE !!!!
    
    
    prime_test<-c(5,7,11,13,17 ,19,23,29,31,37,1009)
    
    for (i in 1:length(prime_test)) {
      print(primeTest(prime_test[i], 50))
    }
    #ALL TRUE
    

2 个答案:

答案 0 :(得分:5)

当然,表示整数存在问题。在R中,整数将正确表示,最大为2 ^ 53 - 1,大约为9e15。即使对于小数字,y^((n-1)/2)一词也会超过这个数字。您必须通过不断平方(y^((n-1)/2)) %% n并取模数来计算y。这对应于(n-1)/2的二进制表示。

即使是'真正的'数论理论程序也是这样做的 - 请参阅维基百科关于“模幂运算”的内容。也就是说应该提到像R(或Matlab和其他数值计算系统)这样的程序可能不是实现数论算法的适当环境,甚至可能不是小整数的播放领域。

编辑:原始包裹不正确 你可以在'pracma'包中使用函数modpower(),如下所示:

primeTest <- function(n, iter){
  a <- sample(1:(n-1), 1)
    lehmannTest <- function(y, tries){
    x <- modpower(y, (n-1)/2, n)  # ((y^((n-1)/2)) %% n)
    if (tries == 0) {
      return(TRUE)
            }else{          
      if ((x == 1) | (x == (-1 %% n))){
        lehmannTest(sample(1:(n-1), 1), (tries-1))
      }else{
    return(FALSE)
      }
    }
  }
  lehmannTest(a, iter)
}

以下测试成功,因为1009是此集合中唯一的素数:

prime_test <- seq(1001, 1011, by = 2)
for (i in 1:length(prime_test)) {
    print(primeTest(prime_test[i], 50))
}
# FALSE FALSE FALSE FALSE TRUE  FALSE

答案 1 :(得分:2)

如果你只是使用基础R,我会选择#2b ......“R对此不好”。在R整数(您似乎没有使用)中限制为16位精度。超过该限制,您将获得舍入错误。你应该看看:package:gmp或package:Brobdingnag。包:gmp有大整数和大理性类。