我花了一点时间来攻击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))
}
Run Code Online (Sandbox Code Playgroud)
对于小素数它可以工作,但是当我到达~30时,我得到一个看起来很糟糕的消息,并且该功能停止正常工作:
2: In lehmannTest(a, iter) : probable complete loss of accuracy in modulus
Run Code Online (Sandbox Code Playgroud)
经过一番调查后,我认为它与浮点转换有关.非常大的数字是四舍五入的,因此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
Run Code Online (Sandbox Code Playgroud)
当然,表示整数存在问题.在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)
}
Run Code Online (Sandbox Code Playgroud)
以下测试成功,因为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
Run Code Online (Sandbox Code Playgroud)