2012-01-09 74 views
2

可能重複失去1:
Why does this double to int conversion not work?轉換雙爲int在C + +

轉換雙爲int在C + +

#include <iostream> 
#include <cmath> 
using namespace std; 

void main() { 

    double num = 1234.34; 
    int numInt = num; 
    double numAfterPoint = num - numInt; // 0.34 

    int counter = 1; 
    double numFloatPower = numAfterPoint; 

    while (true) { 
     numFloatPower = numAfterPoint * pow(10.0, counter); 
     cout << numFloatPower << " > " << (int)numFloatPower << " "; 
     system("pause"); 
     counter++; 
    } 

} 

當前結果失去1:

3.4 > 3 Press any key to continue . . . 
34 > 33 Press any key to continue . . . 
340 > 339 Press any key to continue . . . 
3400 > 3399 Press any key to continue . . . 

的結果應該是:

3.4 > 3 Press any key to continue . . . 
34 > 34 Press any key to continue . . . 
340 > 340 Press any key to continue . . . 
3400 > 3400 Press any key to continue . . . 

等等

+5

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – Anycorn 2012-01-09 09:15:09

+0

您能詳細說明一下這個問題,關於您期待什麼以及您得到什麼。 – 2012-01-09 09:16:36

+0

那麼你的問題是什麼? – larsmoa 2012-01-09 09:16:37

回答

3

浮點運算使用的兩個大國表示任意數量的有限和。諸如3.4之類的數字不完全是兩個冪的和,可能是四捨五入的。在這種情況下,它略微向下取整,說3.39996…。然後當你乘以時,結果將是33.9996…,在圓歸零規則下它將被舍入到33

C++控制檯I/O足夠智能,能夠以最近偶數顯示多少個十進制數字,但計算機的內部數學電路不知道這種情況。它使用值的完整精度,在這種情況下包含錯誤。

嘗試cout << setprecision(20);看到醜陋的真相。

5

的鑄到-INT的操作(int)doubleValue進行截斷,這意味着如果該號碼在內部作爲33.999999999表示...如果您需要執行舍入(3.9將被截斷爲33

round()使用→ 4,3.4→3)。


注:

  • 1234.34實際上是1234.33999999999991814547684044...因爲它不能準確地使用二進制數字數量有限,因此在第53位將被四捨五入
  • 表示因此你的0.34實際上是0.33999999999991814547684044 ...,
  • 您的3.4實際上是3.3999999999991814547684044 ...,
  • 您的34實際上是33.999999999991814547684044 ...,
  • 你的340實際上是339.99999999991814547684044 ...
1

爲了幫助您瞭解發生了什麼事情,讓我給你的使用小數位的固定電話號碼類似的問題,一個很簡單的解釋。 (你遇到的問題是由於固定的二進制位置,這是難以理解的,但問題是相同的。)

您可以做的最好的代表1/3.333333。但現在3 * 1/3 != 1

您可以將2/3表示爲.666666,然後再將2 * 1/3 = 1/3表示爲2/3 + 1/3 != 1

可以代表2/3.666667,然後2/3 + 1/3 = 1,但隨後
2/3 - 1/3 - 1/3 != 02 * 1/3 != 2/3

由於舍入和精度有限,您不應該期望浮點數學生成完全正確的結果。

正如1/3沒有確切的十進制表示,.34沒有確切的二進制表示。

0

由於十進制數通常不是二進制可精確表示的,所以num不是1234.34,而是最接近double的值。那個可能比1234.34稍小(比如1234.33999999999999999999999);在這種情況下,當然numAfterPoint也略小於0.34,使得100 * numAfterPoints看起來小於34等等。由於轉換爲int會刪除小數部分,即使它非常接近1,您也會得到33而不是另一方面,如果直接輸出浮點值,則將四捨五入爲爲特定位數(您可以使用流操縱器進行控制)。因此,除非您告訴流輸出非常多的數字,否則您不會看到區別。嘗試

std::cout << std::setprecision(20) << numAfterPoint << '\n'; 

看到價值是真正存儲

1

麻煩的是你的第一個假設是錯誤的:

​​

現在,如果你設置你的主循環,你會得到下面的號碼精度。

3.3999999999991815 > 3 
33.999999999991815 > 33 
339.99999999991815 > 339 
3399.9999999991815 > 3399 

麻煩的是,該流印刷碼是打印造成它打印3.4而非3.3999999999之前四捨五入的結果。這是因爲3.4不能完全由二進制浮點數表示。