我花了一点时间来攻击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函数给出了错误的响应。
现在问题。
由于
解决方案:
在有关模幂运算算法的大量反馈和一小时阅读后,我有一个解决方案。首先是制作我自己的模幂运算函数。基本思想是模块化乘法允许您计算中间结果。你可以在每次迭代后计算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
答案 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有大整数和大理性类。