为什么我在调用 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"。

这里发生的时间:


当我使用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 宽的东西都是浪费的。