以下是代码,其中limit = 8
:
#include <stdio.h>
#include <math.h> // pow(x, exp)
//----------------------------------------------------------
char isMersenneLucasLehmer(unsigned int prime)
{
unsigned int i, termN = 4;
unsigned long mersenne;
unsigned int limit;
int res;
mersenne = (unsigned long) pow(2, (double)prime) - 1;
if (prime % 2 == 0)
{
return prime == 2;
}
else
{
res = (int) sqrt((double) prime);
for (i = 3; i <= res; i += 2)
{
if (prime % i == 0)
{
return 0;
}
}
limit = prime - 2;
for (i = 1; i <= limit; ++i)
{
termN = (termN * termN - 2) % mersenne;
}
}
return termN == 0;
}
//----------------------------------------------------------
/*
Function: findMersenneLucasLehmer()
*/
void findMersenneLucasLehmer(unsigned int limit)
{
unsigned int i, current = 0;
unsigned long mersenne, bitsInLong = 64;
for (i = 2; i <= bitsInLong; i++)
{
if (current >= limit)
{
break;
}
if (isMersenneLucasLehmer(i))
{
mersenne = (unsigned long) pow(2, (double)i) - 1;
printf("current = %lu, mersenne = %lu, index = %u\n", current, mersenne, i);
++current;
}
}
}
//----------------------------------------------------------
int main()
{
unsigned int limit = 8;
findMersenneLucasLehmer(limit);
return 0;
}
输出:
current = 0, mersenne = 3, index = 2
current = 1, mersenne = 7, index = 3
current = 2, mersenne = 31, index = 5
current = 3, mersenne = 127, index = 7
current = 4, mersenne = 8191, index = 13
它只返回第一个5
而不是8
,我无法弄清楚原因。
它正在从13开始跳过所有索引。我怀疑错误发生在isMersenneLucasLehmer(unsigned int)
的最后几行。我一直盯着看太久而无法找到它。
答案 0 :(得分:3)
termN * termN
处的可能整数溢出。通常,您应该将非常大的数字值表示为双精度数,并且尽可能避免在不同的数字类型之间进行转换,尤其是在整数和浮点数之间进行转换。
答案 1 :(得分:3)
改变这个:
unsigned int termN = 4;
到此:
unsigned long int termN = 4;
主要是因为您稍后执行termN * termN
,当unsigned int
类型时可能会导致溢出。
输出:
current = 0, mersenne = 3, index = 2
current = 1, mersenne = 7, index = 3
current = 2, mersenne = 31, index = 5
current = 3, mersenne = 127, index = 7
current = 4, mersenne = 8191, index = 13
current = 5, mersenne = 131071, index = 17
current = 6, mersenne = 524287, index = 19
current = 7, mersenne = 2147483647, index = 31
按照你应该的方式打印你的类型会很好:
C02QT2UBFVH6-lm:~ gsamaras$ gcc -Wall main.c
main.c:58:67: warning: format specifies type 'unsigned long' but the argument has type 'unsigned int' [-Wformat]
printf("current = %lu, mersenne = %lu, index = %u\n", current, mersenne, i);
~~~ ^~~~~~~
%u
所以将%lu
更改为%u
。
我是如何开始调试的?
在循环开始时使用print语句,如下所示:
for (i = 2; i <= bitsInLong; i++)
{
printf("Loop i = %u, current = %u\n", i, current);
...
你会看到:
current = 4, mersenne = 8191, index = 13
Loop i = 14, current = 5
...
Loop i = 63, current = 5
Loop i = 64, current = 5
这意味着你没有看到8个Mersenne数字,因为你在你的函数fins 8之前你正在结束你的循环!
答案 2 :(得分:2)
问题在于:
termN = (termN * termN - 2) % mersenne;
您将termN
声明为unsigned int
(32位,在您的环境中),但该产品可能会变得如此之大,以至于无法通过此类型表示,并且产生的溢出会导致循环发散。< / p>
解决方案是使用范围更大的类型,例如unsigned long long int
(64位)。
请参阅Ideone.com上的示例。
答案 3 :(得分:2)
让我们进一步推送这个数字并抛出所有浮点代码。虽然下一个mersenne prime适合64位,但问题是termN * termN
表达式在模数可以控制之前会溢出。如果我们有真正的模幂运算,我们可能会避免这个问题。相反,我们在计算该值时会在GCC / clang中使用模拟的128位类型:
#include <stdio.h>
#include <stdbool.h>
typedef unsigned __int128 uint128_t;
bool isPrime(unsigned number)
{
if (number % 2 == 0)
{
return number == 2;
}
for (unsigned i = 3; i * i <= number; i += 2)
{
if (number % i == 0)
{
return false;
}
}
return true;
}
bool isMersenneExponent(unsigned exponent)
{
if (exponent == 2)
{
return true;
}
if (!isPrime(exponent))
{
return false;
}
unsigned long termN = 4, mersenne = (1L << exponent) - 1;
unsigned limit = exponent - 1;
for (unsigned i = 1; i < limit; i++)
{
termN = (((uint128_t) termN * termN) % mersenne) - 2;
}
return termN == 0;
}
void findMersennePrime(unsigned limit)
{
unsigned bit_limit = sizeof(unsigned long) * 8;
for (unsigned current = 0, i = 2; current < limit && i < bit_limit; i++)
{
if (isMersenneExponent(i))
{
unsigned long mersenne = (1L << i) - 1;
printf("current = %u, mersenne = %lu, index = %u\n", current++, mersenne, i);
}
}
}
int main()
{
unsigned limit = 9;
findMersennePrime(limit);
return 0;
}
i * i
中isPrime()
的效率略低,但由于指数素数很小,因此无关紧要。
<强>输出强>
current = 0, mersenne = 3, index = 2
current = 1, mersenne = 7, index = 3
current = 2, mersenne = 31, index = 5
current = 3, mersenne = 127, index = 7
current = 4, mersenne = 8191, index = 13
current = 5, mersenne = 131071, index = 17
current = 6, mersenne = 524287, index = 19
current = 7, mersenne = 2147483647, index = 31
current = 8, mersenne = 2305843009213693951, index = 61