2012-04-17 46 views
18

爲什麼這是真的? Java似乎產生了一個小的差異,當乘以兩個浮點數與C相比,甚至是Java Math.pow方法的結果。Java與C浮點:「x * x」與「pow(x,2)」不同?

的Java:

float a = 0.88276923; 

double b = a * a; // b becomes 0.779281497001648 <---- what??? 
b = Math.pow(a,2); // b becomes 0.7792815081874238 

C:

float a = 0.88276923; 

double b = a * a; // b becomes 0.7792815081874238 
pow(a,2);   // b becomes 0.7792815081874238 

更新:每埃德S.的評論,我還發現了C的行爲取決於編譯器的變化。使用gcc它看起來與Java行爲相匹配。使用visual studio(取決於你的目標平臺),它可以產生上面看到的結果或Java中看到的結果。啊。

+2

http://floating-point-gui.de/ – 2012-04-17 23:37:32

+3

啊,浮點運算。純粹的準確性和可靠性的堡壘。 – Perception 2012-04-17 23:38:43

+1

我知道漂浮不精確。然而,我期望他們的不精確性是一致的。 – mark 2012-04-17 23:40:13

回答

16

由於PST和trutheality已經明智地指出,C是促進floatdouble乘法之前。實際上,當它們被推入堆棧時,它們被提升爲80位的擴展精度值。下面是彙編程序的輸出(VS2005 86 C89)

double b = a * a; 
00411397 fld   dword ptr [a] 
0041139A fmul  dword ptr [a] 
0041139D fstp  qword ptr [b] 

的FLD指令

的FLD指令加載一個32位,64位,或80位浮點值壓入堆棧。 在將值壓入浮點堆棧之前,該指令將32位和64位操作數轉換爲80位擴展精度值


有趣的是,如果我建立目標64時,movss指令使用,你會得到的0.779281497001648值作爲結果,即你看到在你的java例子。試一試。

+2

+1。現在,在C標準的哪裏(並且不要忘記指定哪個草稿!)是否存在一個可以解釋爲實現定義的行爲的vauge語句...... ;-) – 2012-04-17 23:51:11

+2

@pst:我希望我有看看的時間,但是......這是日期晚上:D – 2012-04-17 23:51:38

+0

@pst:試圖將它定位到x64出於好奇,並且當'fld'指令不再使用時(至少在我的設置中),您會看到java行爲。 – 2012-04-17 23:54:31

10

爪哇以什麼

double b = a * a; 

是乘法a * a作爲(32位)float第一個,並且將結果分配給b當轉換爲一個(64位)double

b = Math.pow(a,2); 

將轉換a到一個(64位)double第一(由於用於Math.pow的參數是double, double),然後正方形它。

更令人不解的(對我來說)就是Ç似乎在a的轉換爲double先在

double b = a * a; 

的是,在標準?

編輯:我依稀記得關於C不需要特定的實現(在多少位被用於計算)的數字是......這是怎麼回事呢?你的float是64位嗎? (在Java中,float總是32位,並且double總是64位)。

編輯: Ed S.的答案和標記評論說,不同的編譯器給出不同的結果表明C結果是實現和架構特定的。

+0

我想知道是否還有編譯時評估(優化)? – 2012-04-17 23:47:58

+0

(雖然我懷疑現代機器/編譯器上的sizeof(float)== sizeof(double));-) – 2012-04-17 23:49:02

+0

在我的機器上,當它們被推入堆棧時它們被提升。請參閱:[FLD指令](http://webster.cs.ucr.edu/AoA/Windows/HTML/RealArithmetica2.html) – 2012-04-17 23:51:01