为什么在调用realloc()之后在模运算上出现浮点异常?

时间:2019-06-24 18:14:01

标签: c floating-point gdb primes 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)时,它会返回“浮点异常”。

什么时候发生在这里:

  • 用户选择一个号码。
  • 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的呼叫以避免这种异常吗?

3 个答案:

答案 0 :(得分:3)

  

我认为第一个if语句会解决该问题,因为   printf("%f", primes[tested])打印0。但是,不会,并且   “ break”未执行。

您测试是否为primes[tested] == 0,但是您的代码仅在((int)primes[tested]) == 0时有效。这些根本不是一回事。此外,以格式primes[tested]打印%f的值并不能可靠地告诉您其他信息,因为它只给小数点后6位数字。请尝试使用"%e"格式,并测试您实际需要的条件,而不是相关的较弱的条件。

但更好的是,不要在此处使用浮点类型。 FP与离散数学问题无关,例如您似乎正在尝试解决。如果primes[tested]实际上拥有素数或可能的素数,则unsigned long long int的大小可能与double相同,并且几乎可以肯定地表示更大范围的素数。或者,如果它仅包含标志(例如质数筛),那么任何比char宽的内容都是浪费的。

答案 1 :(得分:2)

非常接近的浮点数仍然不是零。因此,您的等于0检查失败。

请注意,如果您对使用的机器类型不太满意,甚至可以编译

double f = 1.1;
double x = f;
double y = x;

if( y == f )
    puts("This is not always true!");

计算机上的浮点运算很棘手,并且无法按定义编写x等于y等于f的数学公式工作。不,计算机浮点运算适用于位模式,它们必须完全相同

无论如何,回答您的问题。使用与if语句中的if语句完全相同的int类型,它应该可以工作。

realloc返回的新内存也不会自动设置为零。

还有第三个:如果必须使用realloc强制转换(double*)的返回值,则说明您使用的是C ++编译器,应该使用std::vector<double>。真的好多了。否则,如果您正在编写C代码,则编写C代码

答案 2 :(得分:0)

  

我认为第一个if语句将解决该问题,因为   printf(“%f”,primes [test])打印0。

如果此打印语句根据您的发言给出正确的输出,那么显然select typeof(field1), typeof(field2) from cte2 是有意义的。

您正在考虑if语句应该处理异常,但是实际上并没有像您所想的那样执行。首先,它执行with cte1 as (...), cte2 as (... from cte1) describe select * from cte2 部分,然后将结果与Floating point exception进行比较。因此,显然,即使在if可以运行之前,也会发生异常。希望你能理解。

仅供参考,如果i % (int) primes[tested],则0会导致浮点异常。

如果您对if语句的执行步骤有更多疑问,请自己运行以下代码:

b = 0

然后尝试了解哪个a % b首先执行。