涉及威尔逊定理的原始性测试未按计划运行

时间:2011-10-29 03:16:33

标签: c

我刚刚开始编程,我遇到了一个我似乎无法弄清楚的问题。我写了这个函数,isPrime似乎总是通过相等测试。我可以确认factorial函数是有效的,因为我已经单独测试了它。

威尔逊定理指出,如果(p - 1),则数p为素数! + 1是p的倍数。

#include <stdio.h>
#include <math.h>

void isPrime(double p);
double factorial(double n);

int main(void) {
    double userInput;
    while(1) {
        scanf("%lf", &userInput);
        isPrime(userInput);
    }
    return 0;
}

//

double factorial(double n) {
    if(n <= 1)
        return n;
    else
        return n * factorial(n - 1);
}

void isPrime(double p) {
    if(modf(factorial(p - 1) + 1, &p) == 0)
        printf("Prime!\n");
    else
        printf("Not prime!\n");
}

5 个答案:

答案 0 :(得分:4)

不要使用双精度来保持整数。舍入错误将使完全平等的测试变得虚假。请参阅“What Every Computer Scientist Should Know about Floating Point”。

答案 1 :(得分:3)

如果n大于23,则

double无法准确存储因子。从那时起,您的结果将完全是假的。如果你想用威尔逊定理进行素性测试,可以使用模运算,

uint64_t modFactorial(uint64_t n, uint64_t m) {
    uint64_t f = 1;
    for(; n > 1; --n) {
        f = (n*f) % m;
    }
    return f;
}

int isPrime(uint64_t p) {
    if (p < 2) return 0;
    return modFactorial(p-1,p) + 1 == p;
}

可以正确处理小于2 ^ 32的输入。然而,它相当缓慢,威尔逊定理不是在实践中测试素性的好方法,它的价值在于数论中的应用。

如果您需要处理大型整数,请使用GMP(附带 - 概率 - 素数测试)。

答案 2 :(得分:1)

modf不像您期望的那样执行模数。引用:

 The modf() break value into integral and fractional parts, each of which
 has the same sign as the argument.  They return the fractional part, and
 store the integral part (as a floating-point number) in the object
 pointed to by iptr

您希望fmod和朋友代替modf

答案 3 :(得分:0)

您的代码中有一个小错误。

将测试更改为以下内容:

if (modf((factorial(p - 1) + 1)/p, &p) == 0)

另外,正如其他人指出的那样,使用双打可能不是最佳选择。

答案 4 :(得分:-1)

我的猜测是你的阶乘函数返回0因为(n <= 1)允许返回n = 0。