#include <stdio.h>
#include <math.h>
// #define LIMIT 600851475143
int isP(long i);
void run();
// 6857
int main()
{
//int i = 6857;
//printf("%d\n", isP(i));
run();
}
void run()
{
long LIMIT = 600851475143;
// 3, 5
// under 1000
long i, largest =1, temp=0;
for(i=3; i<=775147; i+=2)
{
temp = ((LIMIT/i)*i);
if(LIMIT == temp)
if(isP(i)==1)
largest = i;
}
printf("%d\n",largest);
}
int isP(long i)
{
long j;
for(j=3; j<= i/2; j+=2)
if(i == (i/j)*j)
return 0;
return 1;
}
我刚遇到一个有趣的问题。如上所示,这段代码用于计算LIMIT的最大素数。上面显示的程序给了我29的答案,这是不正确的。
虽然奇迹般地,当我定义LIMIT值(而不是将其声明为长)时,它可以给我正确的值:6857。
有人可以帮我弄清楚原因吗?非常感谢!
答案 0 :(得分:3)
许多平台上的long
是一个4字节整数,并且会在2,147,483,647
溢出。例如,请参阅Visual C++'s Data Type Ranges页面。
当您使用#define
时,编译器可以自由选择一种更合适的类型,它可以保存非常大的数字。这可能会使其表现正常,并为您提供您期望的答案。
但是,一般情况下,我建议明确说明数据类型,并选择能够正确表示数字的数据类型,如果可能的话,不需要编译器和平台特定的行为。
答案 1 :(得分:1)
我怀疑这里有数字类型问题。
#define
是一个预处理程序指令,因此在运行编译器之前,它会在代码中用该数字替换LIMIT
。这使得编译器可以打开门来解释它想要的数字,这可能不是long
。
在您的情况下,long
可能不够大,因此编译器在您使用#define
时会选择其他内容。对于一致的行为,您应该指定一个您知道具有适当范围的类型,而不是依赖编译器进行正确猜测。
您还应该在编译器上启用完整警告,它可能能够为您检测到这类问题。
答案 2 :(得分:1)
输入如下表达式时:
(600851475143 + 1)
一切都很好,因为编译器会自动将这两个常量提升到适当的类型(例如你的long long
),足以执行计算。您可以通过这种方式执行任意数量的表达式。但是当你写道:
long n = 600851475143;
编译器尝试将long long
(或任何常量被隐式转换为)分配给long
,这会导致您的案例出现问题。你的编译器应该警告你这个,gcc例如说:
warning: overflow in implicit constant conversion [-Woverflow]
当然,如果long
大到足以容纳该值,则没有问题,因为常量将是与long
相同或更小的类型。
答案 3 :(得分:0)
可能是因为600851475143
大于LONG_MAX
(根据this 2147483647)
答案 4 :(得分:0)
尝试用'long long'替换限制类型。它的方式,它包裹(尝试打印限制为长)。预处理器知道并使用正确的类型。
答案 5 :(得分:0)
您的代码基本上可以减少这两种可能性:
long LIMIT = 600851475143;
x = LIMIT / i;
VS
#define LIMIT 600851475143
x = LIMIT / i;
第一个相当于将常量强制转换为long
:
x = (long)600851475143 / i;
而第二个将被预编译成:
x = 600851475143 / i;
这就产生了不同之处:600851475143
对于编译器的long
类型来说太大了,所以如果它被强制转换为long
,它会溢出并变得疯狂。但如果直接在分区中使用它,编译器就知道它不适合long
,自动将其解释为long long
字面值,i
被提升并且除法以long long
完成。
但请注意,即使算法似乎在大多数情况下都能正常工作,您仍然会在其他地方出现溢出,因此代码不正确。您应该将任何可能包含这些大值的变量声明为long long
。