簡體   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