2012-07-08 15 views
0

我想乘兩個float S作爲如下:乘以兩個浮體不會給確切的結果

float number1 = 321.12; 
float number2 = 345.34; 
float rexsult = number1 * number2; 

我想看到的結果是110895.582,但是當我運行的代碼,它只是給了我110896大部分時間我都有這個問題。任何計算器都會給我所有小數點的確切結果。我怎樣才能達到那個結果?

編輯:這是C代碼。我正在使用XCode iOS模擬器。

+0

這是C還是Java?它可以來自你所展示的。 – Mysticial 2012-07-08 09:03:07

+0

你應該使用'double'而不是'float'。 – Mysticial 2012-07-08 09:03:29

+0

我也用過雙倍,結果相同。 – ugur 2012-07-08 09:05:01

回答

10

有很多四捨五入的事情。

float a = 321.12; // this number will be rounded 
float b = 345.34; // this number will also be rounded 
float r = a * b; // and this number will be rounded too 
printf("%.15f\n", r); 

經過三次單獨的圓整後我得到了110895.578125000000000。

  1. 如果你想超過6個十進制數字的價值的精確度,你會使用double,而不是float。 (請注意,我說的「小數位數值得」,因爲你沒有得到十進制數字,你得到的二進制)。既然這樣,1/2 ULP誤差(最壞情況開往完美四捨五入的結果)大約是0.004。

  2. 如果你想要的是四捨五入的十進制數字,你將不得不使用一個專門的小數庫這樣的任務。 A double對科學家來說具有足夠的精度,但如果你用錢工作,所有事情都必須100%準確。沒有浮點數的錢。

不像整數,浮點數採取一些實實在在的工作,才能讓習慣了他們的陷阱。請參閱「What Every Computer Scientist Should Know About Floating-Point Arithmetic」,這是該主題的經典介紹。

編輯:其實,我不確定代碼輪了三次。由於ab的常量可能會先舍入爲雙精度,然後在存儲時將它們舍入爲單精度,這可能會輪到五次次。但我不太清楚C這部分的規則。

+0

「它可能四捨五入」確切地說,但對於大多數十進制數,首先舍入爲「double」,然後是「float」與直接舍入爲「float」相同。當我正在尋找1到2之間的無辜十進制數字時,出於http://blog.frama-c.com/index.php?post/2011/11/08/Floatingpoint -quiz,我必須在點後使用14位數字。我找不到只有13位數字。 – 2012-07-08 13:00:53

1

由於您使用的是C,你可以很容易地通過使用「%.xf」,其中x是想要的精確設定的精度。

例如:

float n1 = 321.12; 
float n2 = 345.34; 
float result = n1 * n2; 

printf("%.20f", result); 

輸出:

110895.57812500000000000000 

但是,請注意float只給出精確六位數。爲更好的精確度使用double

1
  • 浮點變量只是近似表示形式,並不精確。並非每個數字都可以「適合」浮點變量。例如,沒有辦法將1/10(0.1)放入二進制變量中,就像不可能將1/3放入十進制小數(只能用無窮大的0.33333來近似)
  • 當輸出這樣的變量時,通常應用許多舍入選項。除非你把它們全部設置好,否則你永遠無法確定它們中的哪一個被應用。這對於運營商而言尤其如此,因爲可以告知流如何在運行之前捨棄< < <。

printf也做了一些四捨五入。考慮http://codepad.org/LLweoeHp

float t = 0.1f; 
printf("result: %f\n", t); 
-- 
result: 0.100000 

好吧,它看起來很好。爲什麼?因爲printf默認了一些精確度並捨去了輸出。我們撥打小數點後50位:http://codepad.org/frUPOvcI

float t = 0.1f; 
printf("result: %.50f\n", t); 
-- 
result: 0.10000000149011611938476562500000000000000000000000 

這是不同的,不是嗎? 625之後,浮動量不足以保存更多數據,這就是爲什麼我們會看到零。 double可以容納更多的數字,但是二進制中的0.1不是有限的。雙不得不放棄,最終:http://codepad.org/RAd7Yu2r

double t = 0.1; 
printf("result: %.70f\n", t); 
-- 
result: 0.1000000000000000055511151231257827021181583404541015625000000000000000 

在你的榜樣,獨自321.12足以引起麻煩:http://codepad.org/cgw3vUKn

float t = 321.12f; 
printf("and the result is: %.50f\n", t); 
result: 321.11999511718750000000000000000000000000000000000000 

這就是爲什麼一個具有呈現在他們面前圍捕浮點值給人類。

計算器程序根本不使用浮動或雙打。它們實現十進制數字格式。例如:

struct decimal 
{ 
    int mantissa; //meaningfull digits 
    int exponent; //number of decimal zeroes 
}; 

需要重新創建所有操作的Ofc:加法,減法,乘法和除法。或者只是尋找一個小數庫。

+0

不,1.0將永遠不會是1.0。四捨五入是以一種非常可預測的方式完成的,任何低於2^24的整數在每一次都會非常準確。 – 2012-07-08 09:25:36

+0

@DietrichEpp:我寫到1.0是一個虛構的例子。 – 2012-07-09 15:53:36

+0

很容易選擇0.1或1/3或100000001.有很多非虛構的例子。 – 2012-07-09 16:14:37

3

你永遠不會得到確切的結果。

首先,number1≠321.12,因爲該值不能在base-2系統中精確表示。你需要無限的位數。

這同樣適用於number2≠345.34。

所以,你首先從不精確的值開始。

然後,產品將變爲四捨五入,因爲乘法會使有效位數增加一倍,但如果乘上浮點數,產品必須再次存儲在float中。

您可能希望爲數字使用基於10的系統。或者,如果您的數字只有小數點的兩位十進制數,則可以使用整數(在這種情況下,32位整數就足夠了,但最終可能需要64位):

32112 * 34534 = 1108955808

這代表321.12 * 345.34 = 110895.5808。