Я потратил немного времени на взлом 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
После некоторых исследований я считаю, что это связано с преобразованиями с плавающей запятой. Очень большие числа округляются, так что функция мода дает плохой ответ.
Теперь вопросы.
- Это проблема с плавающей запятой? или в моей реализации?
- Есть ли чисто R решение или R просто плох в этом?
Спасибо
Решение:
После отличной обратной связи и часового прочтения о алгоритмах модульного возведения в степень у меня есть решение. Во-первых, это сделать мою собственную модульную функцию возведения в степень. Основная идея заключается в том, что модульное умножение позволяет вычислять промежуточные результаты. Вы можете вычислить мод после каждой итерации, таким образом, никогда не получая гигантское противное число, которое забивает 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