2017-03-15 35 views
5

我有以下代碼:差介乎VS2012和VS2015

float a = 0.02f * 28f; 
double b = (double)a; 
double c = (double)(0.02f * 28f); 
Console.WriteLine(String.Format(" {0:F20}", b)); 
Console.WriteLine(String.Format(" {0:F20}", c)); 

然而它返回不同的結果是否它是從VS2012或VS2015編譯(兩者都具有「標準」的設置)

在VS2012

0,56000000238418600000 
0,55999998748302500000 

在VS2015:

0,56000000238418600000 
0,56000000238418600000 

VS2012 dissasembly:

  float a = 0.02f * 28f; 
0000003a mov   dword ptr [ebp-40h],3F0F5C29h 
      double b = (double)a; 
00000041 fld   dword ptr [ebp-40h] 
00000044 fstp  qword ptr [ebp-48h] 
      double c = (double)(0.02f * 28f); 
00000047 fld   qword ptr ds:[001D34D0h] 
0000004d fstp  qword ptr [ebp-50h] 

VS2015 dissasembly:

  float a = 0.02f * 28f; 
001E2DE2 mov   dword ptr [ebp-40h],3F0F5C29h 
      double b = (double)a; 
001E2DE9 fld   dword ptr [ebp-40h] 
001E2DEC fstp  qword ptr [ebp-48h] 
      double c = (double)(0.02f * 28f); 
001E2DEF fld   dword ptr ds:[1E2E7Ch] 
001E2DF5 fstp  qword ptr [ebp-50h] 

正如我們所看到的拆卸是不相同在這兩種情況下,這正常嗎?這可能是VS2012或VS2015中的錯誤嗎?或者這種行爲是由一些被改變的具體設置控制的? 謝謝!

+0

我的第一個猜測是,有對羅斯林和/或不同的不同buildparams。網絡版本導致這個 –

+1

是這個調試或發佈? 64位版本的結果是什麼? 32位構建使用x87,因此它不像SSE2 –

+0

那樣快速且一致,組裝列表相同,但地址相同。數據段選擇器ds:[...]指向一個編譯時常量(顯然,0.02f * 28f的結果會被烘焙到程序集中)。在運行時沒有乘法。 – dlatikay

回答

5

這裏的問題是,在Roslyn編譯器中,在編譯時執行的常量浮點計算與早期版本的執行稍有不同 - 這會導致不同的行爲。

然而,這不是一個錯誤,因爲C#標準的這一部分的:

4.1.6浮點類型

浮點運算可與比結果精度更高來進行操作的類型。例如,某些硬件體系結構支持比double類型更寬的範圍和精度的「extended」或「long double」浮點類型,並隱式執行使用此更高精度類型的所有浮點運算。只有在性能成本過高的情況下,這種硬件體系結構才能以更低的精度執行浮點運算,而不是要求實現放棄性能和精度,C#允許更高精度的類型用於所有浮點運算。除了提供更精確的結果外,這很少有任何可衡量的影響。然而,在x * y/z形式的表達式中,如果乘法產生的結果超出了雙重範圍,但隨後的除法將臨時結果返回到雙重範圍內,則表達式將以更高範圍格式可能會導致產生有限的結果而不是無窮大。要強制浮點類型的值爲其類型的精確精度,可以使用顯式強制類型轉換。

發生了什麼事是你所看到的,從上文中,浮點運算在由羅斯林編譯器編譯時正在做導致不確定的行爲的結果是使用從在編譯時所做的計算不同的精度早期的編譯器。

請注意,在更新2修復的Roslyn編譯器的初始版本中實際存在一個錯誤:https://github.com/dotnet/roslyn/issues/7262 - 但這只是一個感興趣的點,並且與VS2012和VS2015之間的結果差異沒有直接關係(更新2)。

此外詳情參見以下內容:

+0

謝謝!關於錯誤報告的 ,這是否意味着VS2012被竊聽?或2015?或沒有? – lezebulon

+0

@lezebulon VS2015編譯器的第一個版本具有在Update 2中修復的錯誤,但是您看到的結果不同並不是一個錯誤。我澄清了我的答案,使其更清楚。 –

+0

在我看來,這兩種情況下的算術都是在編譯時完成的(這是我所期望的) - 它只是在Roslyn中以一種稍微不同的方式完成。你提到你認爲算術*不是在編譯時完成的「雙重」值......這不是我所看到的 - 你可以進入更多細節嗎? –