簡體   English   中英

C ++ float和int除法奇怪的行為

[英]C++ float and int division strange behaviour

在C ++ Qt庫中,有一個函數QRect screenGeometry() QRect具有int width()int height()函數。 如果我將此函數的結果保存到int變量中,則除法效果很好,但是如果我直接在除法中使用此函數之一,則會得到奇怪的結果:

QRect scr_size = QApplication::desktop()->screenGeometry();
int a = 1280;
int b = 720;
int c = scr_size.width();
int d = scr_size.height();
qDebug() << c; // 1920
qDebug() << d; // 1080
qDebug() << ((float(a) / b) - (float(c) / d)); // 0
qDebug() << ((float(a) / b) - (float(scr_size.width()) / d)); // 1.32455e-08
qDebug() << ((float(a) / b) - (float(c) / scr_size.height())); // 1.32455e-08
qDebug() << ((float(a) / b) - (float(scr_size.width()) / scr_size.height())); // 1.32455e-08

為什么? 以及如何解決?

顯然,正如許多用戶所說,您正在遇到與浮點精度和編譯器相關的優化/選擇有關如何編碼所請求操作的選擇有關的問題。

關鍵在qrect::width()qrect::height()實現中:它們都內聯,這意味着在預處理器之后的行:

((float(a) / b) - (float(scr_size.width()) / d))

將會:

((float(a) / b) - (float(scr_size.x2-scr_size.x1+1) / d))

剩下的就是編譯器如何有效地對目標代碼中的公式進行編碼。

這就是為什么在所有調用qrect成員函數的行中得到不同結果的原因。

供您參考:永遠不要將這種差異與0進行比較,這是一個常見錯誤,請簡單檢查一下絕對值( fabs(x) )是否小於非常小的數字(例如0.0001)。

但是返回int的int變量和函數有什么區別? 為什么結果不同?

編譯器可以自由地做幾件事,這些事情可以結合使用來解釋值的差異:

  • 以任意順序評估完整表達式,必須通過進行函數調用(即使最終以inline結束)也可能會影響該表達式的決策

    • 評估順序可以更改錯誤累積的方式(甚至偶爾相互抵消)
  • 更改評估期間何時將臨時結果存儲在更高精度的寄存器中的決定,例如使用80位CPU寄存器,然后選擇不同的時間取整為32位float

  • 使用與編譯器為您的程序生成的代碼完全不同的優化,CPU指令/寄存器等來評估涉及常量本身的事物,這意味着從1920類的常量移動到僅在運行時才知道的函數調用可能會延遲處理並產生完全不同的結果。

將兩個值相減並檢查0是否等於相等性測試。

由於十進制->二進制轉換和精度限制,使用浮點數的運算不精確 ,因此是對精確相等性的錯誤測試。

可能會發現問題的原因是,在奇怪的結果中查看e-08 1 * 10 ^ -8不是0,而是接近0。更改符號:

1.32455e-08 is 0,0000000132455 which is not 0 but is very near to 0

float在您的平台上是32位。 使用雙打可能會使問題消失。 這將很危險,因為它將隱藏錯誤但無法修復。

暫無
暫無

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

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