簡體   English   中英

接近零的浮動值會導致除以零錯誤嗎?

[英]Can a near-zero floating value cause a divide-by-zero error?

每個人都知道你不應該直接比較浮點數,而是使用公差:

float a,b;
float epsilon = 1e-6f;
bool equal = (fabs(a-b) < epsilon);

我想知道是否同樣適用於在除法之前將值與零進行比較。

float a, b;
if (a != 0.0f) b = 1/a; // oops?

在這種情況下,我還需要與 epsilon 進行比較嗎?

浮點數除以零不是錯誤。 它在支持浮點異常的實現上引發浮點異常(除非您正在主動檢查它們,否則它是無操作的),並且具有明確定義的結果:正無窮大或負無窮大(如果分子非零),或NAN(如果分子為零)。

當分母非零但非常接近於零(例如次正規)時,也可能得到無窮大(和溢出異常)作為結果,但這同樣不是錯誤。 這就是浮點數的工作原理。

編輯:請注意,正如 Eric 在評論中指出的那樣,此答案假定附件 F 的要求,這是 C 標准的可選部分,詳細說明浮點行為並將其與 IEEE 浮點標准保持一致。 在沒有 IEEE 算法的情況下,C 沒有定義浮點除以零(實際上所有浮點運算的結果都是實現定義的,可能定義為完全無意義的,仍然符合 C 標准),所以如果您正在處理不支持 IEEE 浮點的古怪 C 實現,您必須查閱用於回答此問題的實現的文檔。

是的,在某些情況下,除以小數會導致與除以零相同的效果,包括陷阱。

某些 C 實現(和某些其他計算環境)可能會以刷新下溢模式執行,尤其是在使用高性能選項時。 在此模式下,除以次正規可能導致與除以零相同的結果。 使用向量 (SIMD) 指令時,刷新下溢模式並不少見。

次正規數是浮點格式中具有最小指數的數,它們非常小,以至於有效數的隱式位是 0 而不是 1。對於 IEEE 754,單精度,這是幅度小於 2 的非零數-126 對於雙精度,它是幅度小於 2 -1022的非零數字。

正確處理次正規數(根據 IEEE 754)需要在某些處理器中增加計算時間。 為了在不需要時避免這種延遲,處理器可能具有將次正規操作數轉換為零的模式。 將數字除以次正規操作數將產生與除以零相同的結果,即使通常的結果是有限的。

如其他答案中所述,在采用 C 標准附件 F 的 C 實現中,除以零並不是錯誤。 並非所有實現都這樣做。 在不這樣做的實現中,如果沒有關於您的環境的額外規范,您無法確定是否啟用了浮點陷阱,特別是被零除異常的陷阱。

根據您的情況,您可能還必須防止應用程序中的其他代碼更改浮點環境。

回答你帖子標題中的問題,除以很小的數字不會導致除以零,但可能會導致結果變成無窮大:

double x = 1E-300;
cout << x << endl;
double y = 1E300;
cout << y << endl;
double z = y / x;
cout << z << endl;
cout << (z == std::numeric_limits<double>::infinity()) << endl;

會產生以下輸出:

1e-300
1e+300
inf
1

只有除以 0.f 才會引發除以零異常。

然而,除以一個非常小的數字會產生溢出異常——結果太大以至於不能再用浮點數來表示。 除法將返回無窮大。

無窮大的浮點表示可用於計算,因此如果您的其余實現可以處理它,則可能不需要檢查它。

在這種情況下,我還需要與 epsilon 進行比較嗎?

您永遠不會收到除以零的錯誤,因為0.0fIEEE float 中精確表示。

話雖如此,您可能仍然希望使用一些容差 - 盡管這完全取決於您的應用程序。 如果“零”值是其他數學運算的結果,則可能會得到一個非常小的非零數,這可能會導致除法后出現意外結果。 如果您想將“接近零”的數字視為零,則容差是合適的。 但是,這完全取決於您的應用程序和目標。

如果您的編譯器使用IEEE 754 標准進行異常處理,則除以零以及除以小到足以導致溢出的值都將導致值 +/- infiniti。 這可能意味着您可能希望對非常小的數字進行檢查(這會導致您的平台溢出)。 例如,在Windows 上floatdouble都符合規范,這可能會導致非常小的除數創建 +/- infiniti,就像零值一樣。

如果您的編譯器/平台不遵循 IEEE 754 浮點標准,那么我相信結果是特定於平台的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM