为什么我在调用 realloc() 后得到模运算的浮点异常?
Why do I get a floating-point exception on modulo operation after a call to realloc()?
我写这段代码是为了找到第 x 个最大的素数:
for (int i = 3 /* 2 has already been added to the list */; i < maxNumber; i += 2) {
for (int tested = 0; ; tested++) {
if (primes[tested] == 0) {
break;
}
if (i % (int) primes[tested] == 0) {
goto loop;
}
}
count++;
if (count == primesSize) {
primesSize += 2000;
primes = (double*) realloc(primes, sizeof(double) * primesSize);
}
primes[count - 1] = i;
printf("Prime number #%d: %d\n", count, i);
printf("Prime size: %d\n", primesSize);
loop: /* statement that does nothing */ if (1) {}
}
然而,当使用大数字(> 8,000)时,它返回 "Floating point exception"。
这里发生的时间:
- 用户选择一个号码。
maxNumber
设置为所选数字的平方根。
- 首先,分配一个大小为
1000 * sizeof(double)
的双指针。它存储在 primes
变量中。
- 如果发现一个数是质数,则将其添加到指针所代表的数组中。
- 当第 1,000 个数字添加到数组时,
primes
指针被重新分配以存储另外 2,000 个数字。
当我使用gdb
查找错误原因时,发现这部分是问题的原因:
for (int tested = 0; ; tested++) {
if (primes[tested] == 0) {
break;
}
if (i % (int) primes[tested] == 0 /* breaks here */) {
goto loop;
}
}
更新: 我认为第一个 if
语句会捕获该问题,因为 printf("%f", primes[tested])
打印 0。但是,它没有并且 "break"没有执行。
当代码中断时,tested
为 1001。我将 primes[tested]
转换为整数,因为我使用的 modulo arithmetic operation 需要整数才能工作。但是,当我从代码中打印 primes[tested]
时,它显示 0。如果我从 gdb 打印值,我得到 6.1501785659964211e-319.
我错过了什么?我是否应该修改对 realloc
的调用以避免此异常?
I thought the first if statement would catch that issue, because
printf("%f", primes[tested]) prints 0.
如果这个 print 语句根据您所说的给出正确的输出,那么显然 Floating point exception
是有道理的。
您认为 if 语句应该处理异常,但实际上并没有按照您的想法执行。首先它执行 i % (int) primes[tested]
部分,然后将结果与 0
进行比较。因此,显然异常甚至在 if 可以运行之前就发生了。希望你明白。
仅供参考,如果 b = 0
,则 a % b
会导致浮点异常。
而如果你对if语句的执行步骤有更多疑惑,那么运行自己这段代码:
if (printf("Hello") == 5) {
printf(" World");
}
然后尝试了解哪个 printf()
先执行。
非常接近 零的浮点数仍然不完全为零。所以你对等于零的检查失败了。
请注意,如果您在您编译的机器类型上运气不佳,甚至可以
double f = 1.1;
double x = f;
double y = x;
if( y == f )
puts("This is not always true!");
计算机上的浮点数学运算很棘手,并且不能像您期望的那样在数学中编写数学运算,其中根据定义 x 等于 y 等于 f。不,计算机浮点数适用于位模式,它们必须完全相同。
总之,回答你的问题。在您的 if 语句中使用与在您的模数中完全相同的 int 转换,它应该可以工作。
而且从 realloc
编辑的新内存 return 不会自动设置为零。
还有第三个:如果您必须使用 (double*)
从 realloc
转换 return,那么您使用的是 C++ 编译器,应该使用 std::vector<double>
.真的好多了。否则,如果您正在编写 C 代码,那么 编写 C 代码。
I thought the first if
statement would catch that issue, because
printf("%f", primes[tested])
prints 0. However, it doesn't and the
"break" is not executed.
你测试是否primes[tested] == 0
,但你的代码只有在((int)primes[tested]) == 0
时才有效。这些根本不是一回事。此外,以 %f
格式打印 primes[tested]
的值并不能可靠地告诉您不同之处,因为它只给您小数点后 6 位数字。尝试使用 "%e"
格式,并测试您实际需要的条件,而不是相关的、较弱的条件。
但更好的是,不要在此处使用 floating-point 类型。 FP 没有用于离散数学问题的业务,例如您似乎要解决的问题。如果 primes[tested]
实际上包含质数或 possibly-prime 数,那么 unsigned long long int
可能与 double
具有相同的大小,并且几乎可以肯定可以准确地表示更广泛的质数。或者如果它只包含标志,例如在素数筛中,那么任何比 char
宽的东西都是浪费的。
我写这段代码是为了找到第 x 个最大的素数:
for (int i = 3 /* 2 has already been added to the list */; i < maxNumber; i += 2) {
for (int tested = 0; ; tested++) {
if (primes[tested] == 0) {
break;
}
if (i % (int) primes[tested] == 0) {
goto loop;
}
}
count++;
if (count == primesSize) {
primesSize += 2000;
primes = (double*) realloc(primes, sizeof(double) * primesSize);
}
primes[count - 1] = i;
printf("Prime number #%d: %d\n", count, i);
printf("Prime size: %d\n", primesSize);
loop: /* statement that does nothing */ if (1) {}
}
然而,当使用大数字(> 8,000)时,它返回 "Floating point exception"。
这里发生的时间:
- 用户选择一个号码。
maxNumber
设置为所选数字的平方根。- 首先,分配一个大小为
1000 * sizeof(double)
的双指针。它存储在primes
变量中。 - 如果发现一个数是质数,则将其添加到指针所代表的数组中。
- 当第 1,000 个数字添加到数组时,
primes
指针被重新分配以存储另外 2,000 个数字。
- 当第 1,000 个数字添加到数组时,
当我使用gdb
查找错误原因时,发现这部分是问题的原因:
for (int tested = 0; ; tested++) {
if (primes[tested] == 0) {
break;
}
if (i % (int) primes[tested] == 0 /* breaks here */) {
goto loop;
}
}
更新: 我认为第一个 if
语句会捕获该问题,因为 printf("%f", primes[tested])
打印 0。但是,它没有并且 "break"没有执行。
当代码中断时,tested
为 1001。我将 primes[tested]
转换为整数,因为我使用的 modulo arithmetic operation 需要整数才能工作。但是,当我从代码中打印 primes[tested]
时,它显示 0。如果我从 gdb 打印值,我得到 6.1501785659964211e-319.
我错过了什么?我是否应该修改对 realloc
的调用以避免此异常?
I thought the first if statement would catch that issue, because printf("%f", primes[tested]) prints 0.
如果这个 print 语句根据您所说的给出正确的输出,那么显然 Floating point exception
是有道理的。
您认为 if 语句应该处理异常,但实际上并没有按照您的想法执行。首先它执行 i % (int) primes[tested]
部分,然后将结果与 0
进行比较。因此,显然异常甚至在 if 可以运行之前就发生了。希望你明白。
仅供参考,如果 b = 0
,则 a % b
会导致浮点异常。
而如果你对if语句的执行步骤有更多疑惑,那么运行自己这段代码:
if (printf("Hello") == 5) {
printf(" World");
}
然后尝试了解哪个 printf()
先执行。
非常接近 零的浮点数仍然不完全为零。所以你对等于零的检查失败了。
请注意,如果您在您编译的机器类型上运气不佳,甚至可以
double f = 1.1;
double x = f;
double y = x;
if( y == f )
puts("This is not always true!");
计算机上的浮点数学运算很棘手,并且不能像您期望的那样在数学中编写数学运算,其中根据定义 x 等于 y 等于 f。不,计算机浮点数适用于位模式,它们必须完全相同。
总之,回答你的问题。在您的 if 语句中使用与在您的模数中完全相同的 int 转换,它应该可以工作。
而且从 realloc
编辑的新内存 return 不会自动设置为零。
还有第三个:如果您必须使用 (double*)
从 realloc
转换 return,那么您使用的是 C++ 编译器,应该使用 std::vector<double>
.真的好多了。否则,如果您正在编写 C 代码,那么 编写 C 代码。
I thought the first
if
statement would catch that issue, becauseprintf("%f", primes[tested])
prints 0. However, it doesn't and the "break" is not executed.
你测试是否primes[tested] == 0
,但你的代码只有在((int)primes[tested]) == 0
时才有效。这些根本不是一回事。此外,以 %f
格式打印 primes[tested]
的值并不能可靠地告诉您不同之处,因为它只给您小数点后 6 位数字。尝试使用 "%e"
格式,并测试您实际需要的条件,而不是相关的、较弱的条件。
但更好的是,不要在此处使用 floating-point 类型。 FP 没有用于离散数学问题的业务,例如您似乎要解决的问题。如果 primes[tested]
实际上包含质数或 possibly-prime 数,那么 unsigned long long int
可能与 double
具有相同的大小,并且几乎可以肯定可以准确地表示更广泛的质数。或者如果它只包含标志,例如在素数筛中,那么任何比 char
宽的东西都是浪费的。