[英]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_point和http://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.