簡體   English   中英

如何避免C ++中的浮點數舍入問題?

[英]How can I avoid this float number rounding issue in C++?

使用下面的代碼,我得到結果“ 4.31 43099”。

  double f = atof("4.31");
  long ff = f * 10000L;
  std::cout << f << ' ' << ff << '\n';

如果我將“ double f”更改為“ float f”。 我得到預期的結果“ 4.31 43100”。 我不確定將“ double”更改為“ float”是否是一個好的解決方案。 有什么好的解決方案可以確保我得到“ 43100”?

您將無法消除浮點運算中的誤差(盡管通過適當的分析您可以計算出誤差)。 對於臨時使用,您可以做的一件事以獲得更直觀的結果,就是用常規舍入替換內置的float到整型轉換(執行截斷):

double f = atof("4.31");
long ff = std::round(f * 10000L);
std::cout << f << ' ' << ff << '\n';

這應該輸出您期望的結果: 4.31 43100


同樣,使用10000L也沒有意義,因為無論您使用哪種整數類型,它都仍會轉換為f的浮點類型進行乘法運算。 只需使用std::round(f * 10000.0);

問題在於,在談論十進制數字時,浮點本質上是不精確的。 十進制數轉換為二進制數時可以向上或向下舍入,具體取決於哪個值最接近。

在這種情況下,您只想確保如果將數字四舍五入,則將其四舍五入。 您可以通過在該值中添加盡可能小的值來完成此操作,如果您使用的是C ++ 11,則可以使用nextafter函數完成此操作:

long ff = std::nextafter(f, 1.1*f) * 10000L;

如果您沒有nextafter ,則可以使用numeric_limits進行近似。

long ff = (f * (1.0 + std::numeric_limits<double>::epsilon())) * 10000L;

我剛剛看到您的評論,即您僅使用小數點后4位,因此這會更簡單但更不可靠:

long ff = (f * 1.0000001) * 10000L;

使用標准C類型-我懷疑。

在這些位中不能表示很多值,它們實際上需要存儲更多的空間。 因此,浮點處理器只使用最接近的值。

浮點數不能存儲您認為可能的所有值-位數有限-您不能在32位中輸入超過40億個不同的值。 那只是第一個限制。

浮點值(以C表示)表示為: sign - one sign bit, power - bits which defines the power of two for the number, significand - the bits that actually make the number

您的實際數字是sign * significand * 2 inpowerof(power - normalization).

Double是1位符號,15位冪(歸一化為正,但不是點)和48位代表該值;

表示所有值很多,但還不夠,尤其是當它們不能輕易地表示為二的冪的有限和時:尤其是當它們是二進制1010.101101(101)時。 例如,它不能精確表示1/3 = 0.333333(3)之類的值。 這是第二個限制。

嘗試閱讀-對浮點算術的優缺點的適當理解可能非常方便: http//en.wikipedia.org/wiki/Floating_pointhttp://homepage.cs.uiowa.edu/~atkinson/m170。 DIR / overton.pdf

這里有些困惑的答案! 這是怎么回事:4.31不能完全表示為單精度或雙精度數字。 事實證明,最接近可表示的單精度數略大於4.31,而最接近可表示的雙精度數略小於4.31。 將浮點值分配給整數變量時,會將其舍入為零(而不是最接近的整數!)。

因此,如果f為單精度,則f * 10000L大於43100,因此將其舍入為43100。如果f為雙精度,則f * 10000L小於43100,因此將其舍入為43099。

nm的評論建議f * 10000L + 0.5 ,這是我認為最好的解決方案。

暫無
暫無

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

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