[英]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,或者甚至是子表達式的任意多余精度和任意舍入到標稱精度)。
你擔心的問題是:
0.125
不完全是1/8,和 +
不是完全數學加法。 對於這個特定的程序,這些都不會發生。 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標准。 您的代碼不正常,因為:
想象一下,有人不知道這個要求,也不用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.