Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 浮点数的重复递增_C_Floating Point - Fatal编程技术网

C 浮点数的重复递增

C 浮点数的重复递增,c,floating-point,C,Floating Point,我正在看一些遗留代码,这些代码定义了沿轴f的一些网格点 int main(){ double f[9]; int i = 0; for (double a = 0; a <= 1; a += 0.125){ f[i++] = a; } } intmain(){ 双f[9]; int i=0; 对于(double a=0;a当使用C编译器进行编译时,该代码可以提供准确的IEEE 754语义或它们的近似值(例如,FLT_EVAL_METHOD>

我正在看一些遗留代码,这些代码定义了沿轴
f
的一些网格点

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

对于(double a=0;a当使用C编译器进行编译时,该代码可以提供准确的IEEE 754语义或它们的近似值(例如,FLT_EVAL_METHOD>0,甚至子表达式的任意超额精度和任意舍入到标称精度)

你担心的问题是:

  • 表示错误,其中
    0.125
    不完全是1/8,以及
  • 操作错误,其中
    +
    不完全是数学加法。这些都不会发生在这个特定的程序中
  • 0.125要求1位精度以基数2精确表示。这意味着程序在这些条件下使用的浮点数正好是预期的1/8。此外,在加法中存在任何近似值之前,可以将其自身相加253次


    此推理不适用于其他增量步骤。例如,以下程序的变体使数组的一个索引
    f[100]
    ,至少未使用我的编译器(实现严格的IEEE 754语义)初始化:

    intmain(){
    双f[101];
    int i=0;
    
    对于(双a=0;aC标准保留浮点数实现的行为,许多编译器使用IEEE 754标准。您的代码不正常,因为:

  • 您的代码必须使用IEEE 754标准或具有相同行为的类似标准编译
  • 很难阅读。当你阅读代码时,确切的行为并不明显
  • 这不是在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;
      }
    }
    
    #包括
    内部主(空){
    双f[9];
    size\t const size\u f=sizeof f/sizeof*f;
    双a=0;
    对于(大小i=0;i
    是的,这太糟糕了,你应该总是使用数组边界进行迭代-其他所有事情都会带来麻烦其他人所说的都是100%正确的。也就是说,值得指出的是0.125是2的精确幂,所以这段代码在任何非深奥的平台上都能正常工作。不,这段代码不好,因为它不明显。“在最初的版本中,double a是在循环之外声明的,我正在阅读原因。”如果我没记错的话,在C99之前,您必须这样做。这非常令人放心。感谢您的回答。虽然您的答案完全正确,但我希望看到一些人提到它绝对不是好代码。在(可能是理论上的)使用BCD算术和表示法的机器,很可能无法工作,例如增量为1/10而不是1/8时,也无法工作。编写一个循环,使其以一个增量而不是另一个增量正常工作是不好的做法。@tofro我避免讨论StackOverflow的样式,但事实上在程序中只调用几个常量,似乎是无意的,使它停止了预期的工作。我添加了一个例子。另一种可能的错误,对
    f
    的越界写入,需要一个循环,需要更多的迭代(累积的错误必须与增量相当)@Stargateur如果你不理解浮点运算的原理,那就错了。你也可以对(inti=0;i!=200;i+=2)说
    是错误的,应该使用
    @Stargateur注意,您将我的答案中的句子缩短了。还要注意声明
    int x=40000;
    具有实现定义的行为。虽然在任何符合标准的编译器上编写行为相同的代码并非不可能,但这样的练习类似于在一种深奥的语言。在实践中,没有一段重要的C代码不依赖于实现定义的行为。所以所有的否决票,都是循环使用
    double
    来填充数组的人吗?我可以接受。 ... 9.8000000000000065e-01 98 9.9000000000000066e-01 99
    #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;
      }
    }