繁体   English   中英

重复递增浮点数

[英]Repeated incrementation of a floating point number

我正在查看一些遗留代码,它们定义了沿轴f一些网格点。

int main(){
    double f[9];
    int i = 0;
    for (double a = 0; a <= 1; a += 0.125){
        f[i++] = a;
    }
}

我担心重复添加1/8到a ,并且循环没有正确运行。 这是因为我认为你不能像这样添加浮点值,并且当i是8时它依赖于它正好是1。

或者这段代码是否正常,我应该停止担心? (代码显然至少已有20年历史,并且从未造成过麻烦 - 尽管在原始版本中,在循环之外声明了double a ,我正在阅读为什么会这样。)。

当使用C编译器编译时,代码很好,C编译器提供精确的IEEE 754语义或它们的近似值(例如,FLT_EVAL_METHOD> 0,或者甚至是子表达式的任意多余精度和任意舍入到标称精度)。

你担心的问题是:

  1. 表示错误,其中0.125不完全是1/8,和
  2. 操作错误,其中+不是完全数学加法。 对于这个特定的程序,这些都不会发生。

0.125要求1位精度在基数2中精确表示。这意味着程序在这些条件下使用的浮点数恰好是预期的1/8。 此外,在添加任何近似值之前,它可以添加到自身2 53次。


这种推理对于其他增量步骤是不正确的。 例如,下面的程序的变化留下了一个数组的索引, f[100] ,至少与我的编译器(实现严格的IEEE 754语义)未初始化:

int main(){
    double f[101];
    int i = 0;
    for (double a = 0; a <= 1; a += 0.01){
        printf("%.16e %d\n", a, i);
        f[i++] = a;
    }
}

当我运行它时,我得到最后一行:

...
9.8000000000000065e-01 98
9.9000000000000066e-01 99

f[100]永远不会被写入,因为尝试在二进制浮点中重复添加0.01时会出现表示错误和操作错误。

C标准叶子浮点数实现了行为 ,很多编译器使用IEEE 754标准。 您的代码不正常,因为:

  1. 您的代码必须使用IEEE 754标准或具有相同行为的类似标准进行编译。
  2. 这很难读。 当您阅读代码时,确切的行为并不明显。
  3. 这不是在C中迭代数组的正确方法。

想象一下,有人不知道这个要求,也不用IEEE 754标准编译。 这种行为可能完全不同。 例如,您的代码可能会产生越界,这是未定义的行为,您的程序可能会崩溃。


也就是说,使用IEEE 754标准编译时代码行为相同的代码示例:

#include <stddef.h>

int main(void) {
  double f[9];
  size_t const size_f = sizeof f / sizeof *f;

  double a = 0;
  for (size_t i = 0; i < size_f; i++) {
    f[i] = a;
    a += 0.125;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM