C#/ .NET浮點操作在調試模式和釋放模式之間的精度有所不同嗎?調試/釋放模式下的浮點/雙精度
回答
他們確實可以是不同的不同。根據CLR ECMA規範:
存儲位置浮點 數字(靜力學,數組元素,和類的 字段)是固定大小。 支持的存儲大小爲 float32和float64。其他地方 (在評估堆棧上,如 自變量,返回類型和 局部變量)浮點數 使用內部浮點類型 表示。在每個 這樣的實例中,變量或表達式的標稱類型是R4或 R8,但其值可以在內部表示爲 並且附加範圍爲 和/或精度。 內部浮點表示 的大小取決於實現,可能會有所不同,並且其精度應至少如表示的變量或 表達式那樣大。 從float32 或float64的內部表示的隱式擴展轉換爲 類型從存儲中加載時執行。 內部表示通常爲 硬件的本地大小,或 執行操作所需的 。
什麼這基本上意味着,下面的對比可能會或可能不等於:
class Foo
{
double _v = ...;
void Bar()
{
double v = _v;
if(v == _v)
{
// Code may or may not execute here.
// _v is 64-bit.
// v could be either 64-bit (debug) or 80-bit (release) or something else (future?).
}
}
}
拿回家的消息:從不檢查平等的浮動值。
它們應該是一樣的。浮點數基於IEEE_754 standard。
事實上,如果調試模式使用x87 FPU並且發佈模式將SSE用於float-ops,則它們可能會有所不同。
你有權威的參考或示範? – 2008-09-18 07:52:43
針對上述(在評論)弗蘭克·克魯格的請求差的示範:
編譯GCC這個代碼沒有優化和-mfpmath = 387(我沒有理由認爲它不會在其他編譯器上工作,但我沒有嘗試過。) 然後在不進行優化的情況下進行編譯,並使用-msse -mfpmath = sse進行編譯。
輸出會有所不同。
#include <stdio.h>
int main()
{
float e = 0.000000001;
float f[3] = {33810340466158.90625,276553805316035.1875,10413022032824338432.0};
f[0] = pow(f[0],2-e); f[1] = pow(f[1],2+e); f[2] = pow(f[2],-2-e);
printf("%s\n",f);
return 0;
}
謝謝你們我發現一對夫婦的文章說什麼什麼做花車的行爲將在釋放模式
http://blogs.msdn.com/davidnotario/archive/2005/08/08/449092.aspx
這是一個有趣的問題,所以我做了一些實驗。我用這個代碼:
static void Main (string [] args)
{
float
a = float.MaxValue/3.0f,
b = a * a;
if (a * a < b)
{
Console.WriteLine ("Less");
}
else
{
Console.WriteLine ("GreaterEqual");
}
}
使用DevStudio的2005和.Net 2.我編譯爲調試版本和發佈,並檢查了編譯器的輸出:
Release Debug
static void Main (string [] args) static void Main (string [] args)
{ {
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,3Ch
00000009 xor eax,eax
0000000b mov dword ptr [ebp-10h],eax
0000000e xor eax,eax
00000010 mov dword ptr [ebp-1Ch],eax
00000013 mov dword ptr [ebp-3Ch],ecx
00000016 cmp dword ptr ds:[00A2853Ch],0
0000001d je 00000024
0000001f call 793B716F
00000024 fldz
00000026 fstp dword ptr [ebp-40h]
00000029 fldz
0000002b fstp dword ptr [ebp-44h]
0000002e xor esi,esi
00000030 nop
float float
a = float.MaxValue/3.0f, a = float.MaxValue/3.0f,
00000000 sub esp,0Ch 00000031 mov dword ptr [ebp-40h],7EAAAAAAh
00000003 mov dword ptr [esp],ecx
00000006 cmp dword ptr ds:[00A2853Ch],0
0000000d je 00000014
0000000f call 793B716F
00000014 fldz
00000016 fstp dword ptr [esp+4]
0000001a fldz
0000001c fstp dword ptr [esp+8]
00000020 mov dword ptr [esp+4],7EAAAAAAh
b = a * a; b = a * a;
00000028 fld dword ptr [esp+4] 00000038 fld dword ptr [ebp-40h]
0000002c fmul st,st(0) 0000003b fmul st,st(0)
0000002e fstp dword ptr [esp+8] 0000003d fstp dword ptr [ebp-44h]
if (a * a < b) if (a * a < b)
00000032 fld dword ptr [esp+4] 00000040 fld dword ptr [ebp-40h]
00000036 fmul st,st(0) 00000043 fmul st,st(0)
00000038 fld dword ptr [esp+8] 00000045 fld dword ptr [ebp-44h]
0000003c fcomip st,st(1) 00000048 fcomip st,st(1)
0000003e fstp st(0) 0000004a fstp st(0)
00000040 jp 00000054 0000004c jp 00000052
00000042 jbe 00000054 0000004e ja 00000056
00000050 jmp 00000052
00000052 xor eax,eax
00000054 jmp 0000005B
00000056 mov eax,1
0000005b test eax,eax
0000005d sete al
00000060 movzx eax,al
00000063 mov esi,eax
00000065 test esi,esi
00000067 jne 0000007A
{ {
Console.WriteLine ("Less"); 00000069 nop
00000044 mov ecx,dword ptr ds:[0239307Ch] Console.WriteLine ("Less");
0000004a call 78678B7C 0000006a mov ecx,dword ptr ds:[0239307Ch]
0000004f nop 00000070 call 78678B7C
00000050 add esp,0Ch 00000075 nop
00000053 ret }
} 00000076 nop
else 00000077 nop
{ 00000078 jmp 00000088
Console.WriteLine ("GreaterEqual"); else
00000054 mov ecx,dword ptr ds:[02393080h] {
0000005a call 78678B7C 0000007a nop
} Console.WriteLine ("GreaterEqual");
} 0000007b mov ecx,dword ptr ds:[02393080h]
00000081 call 78678B7C
00000086 nop
}
什麼上面所示的是浮動點編碼對於調試和發佈都是相同的,編譯器在優化上選擇一致性。儘管程序產生錯誤的結果(a * a不小於b),但不管調試/釋放模式如何,它都是相同的。現在
,英特爾IA32 FPU有八個浮點寄存器,你會認爲優化的時候,而不是寫內存,從而提高性能,沿着線的東西,編譯器將使用寄存器來存儲值:
fld dword ptr [a] ; precomputed value stored in ram == float.MaxValue/3.0f
fmul st,st(0) ; b = a * a
; no store to ram, keep b in FPU
fld dword ptr [a]
fmul st,st(0)
fcomi st,st(0) ; a*a compared to b
但這將執行不同於調試版本(在這種情況下,顯示正確的結果)。但是,根據構建選項更改程序的行爲是非常糟糕的事情。
FPU代碼是手工編寫代碼可以顯着優於編譯器的一個領域,但您確實需要圍繞FPU的工作方式開展工作。
- 1. 在發佈模式/調試模式下雙精度的差異
- 2. 雙精度和單精度浮點數?
- 3. 爪哇 - 雙精度浮點
- 4. 雙精度浮點數和其他浮點數精度
- 5. 雙精度浮點數如何轉換爲單精度浮點格式?
- 6. 雙精度浮點值傳遞雙精度時
- 7. 雙精度和浮點的含義?
- 8. Java中的雙精度浮點型
- 9. c中的浮點數和雙精度#
- 10. iphone在調試模式下釋放內存但不在釋放模式下
- 11. 「雙精度浮點格式」有多精確?
- 12. 浮點精度格式
- 13. 浮點和雙精度恆定比較
- 14. 將雙精度轉換爲浮點數
- 15. Objective-C浮點數/雙精度
- 16. 專門爲雙精度和浮點精度的java類
- 17. 標準雙精度IEEE浮點數有多少位的精度?
- 18. 單精度大端浮點值到Python浮點數(雙精度,大端)
- 19. AdaGide:調試模式和釋放模式
- 20. 浮點精度
- 21. 雙精度10點精度
- 22. 作爲兩個雙打總和的雙雙精度浮點數
- 23. 是否有可能以保真度將浮點雙精度浮點雙精度到兩個十進制整數?
- 24. 浮法arithemtic和雙精度?
- 25. 無法在Scala中寫入雙精度浮點和雙精度浮點數的方法
- 26. 雙精度浮點格式的最大和最小指數
- 27. 雙精度浮標的雙精度數字
- 28. FIT測試中的浮點精度
- 29. 是在開普勒圖形上模擬雙精度浮點嗎?
- 30. 與浮點精度
你爲什麼認爲他們不同? – 2008-09-18 07:44:26
是的,我有興趣瞭解你的思維過程。 – 2008-09-18 07:50:16
問題是關於調試和發佈之間的區別。你會認爲發佈版本會使用寄存器而不是RAM,這會更高精度:FPU = 80bit,double = 64bit,float = 32bit。 – Skizz 2008-09-18 09:03:12