簡體   English   中英

為什么除法結果會根據演員類型而有所不同?

[英]Why does a division result differ based on the cast type?

這是我不理解的代碼的一部分:

byte b1 = (byte)(64 / 0.8f); // b1 is 79
int b2 = (int)(64 / 0.8f); // b2 is 79
float fl = (64 / 0.8f); // fl is 80

為什么前兩個計算一個一個? 我應該如何執行此操作,所以它快速而正確?

編輯:我需要字節結果

編輯:不完全正確,請參閱: 為什么除法結果會根據演員類型而有所不同? (跟進)

舍入問題:通過轉換為byte / int,您將剪切小數位。

64 / 0.8不應該導致任何小數位? 錯誤:由於浮點數的性質,0.8f不能完全像內存中的那樣表示; 它被存儲為接近0.8f的東西(但不完全是)。 請參閱浮點不准確示例或類似線程。 因此,計算結果不是80.0f,而是79.xxx,其中xxx接近1但仍然不是一個。

您可以通過在Visual Studio中的立即窗口中鍵入以下內容來驗證這一點:

(64 / 0.8f)
80.0
(64 / 0.8f) - 80
-0.0000011920929
100 * 0.8f - 80
0.0000011920929

你可以通過使用舍入來解決這個問題:

byte b1 = (byte)(64 / 0.8f + 0.5f);
int b2 = (int)(64 / 0.8f + 0.5f);
float fl = (64 / 0.8f);

在這樣的情況下,我擔心快速和正確是不一致的。

由於我們的CPU架構中的底層表示,二進制浮點運算幾乎總是會產生小錯誤。 所以在你的初始表達式中,你實際得到的值比數學上正確的值小一點。 如果你期望一個整數作為特定數學運算的結果並且你得到一些非常接近它的東西,你可以使用Math.Round(Double, MidpointRounding)方法來執行正確的舍入並補償小錯誤(並確保你選擇你期望的MidpointRounding策略

簡單地將結果轉換為諸如byteint類的類型不會進行舍入 - 它只是切斷小數部分(當你將它轉換為這些類型時,甚至1.99999f將變為1 )。

十進制浮點運算速度較慢且占用內存較多,但不會導致這些錯誤。 要執行它,請使用decimal literals而不是float literals(例如64 / 0.8m )。

經驗法則是:

  • 如果您正在處理確切數量(通常是人為的,如錢),請使用decimal
  • 如果您處理的是不精確的數量(如分數物理常數或π等無理數),請使用double
  • 如果您正在處理不精確的數量(如上所述)並且可以進一步犧牲一些准確性(例如使用圖形時),請使用float

要理解該問題,您需要了解浮點表示和操作的基礎知識。

0.8f無法使用浮點數在內存中精確表示。

在數學中,64 / 0.8等於80.在浮點算術中,60 / 0.8約等於80。

將浮點數轉換為整數或字節時,僅保留數字的整數部分。 在您的情況下,浮點除法的不精確結果略小於80,因此轉換為整數產生79。

如果你需要一個整數結果,我建議你舍入結果而不是轉換結果。 一種方法是使用以下函數,通過舍入到最接近的整數轉換為整數:

Convert.ToInt32(64/0.8f);

暫無
暫無

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

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