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. c中的浮点数和双精度#
- 6. 双精度和浮点的含义?
- 7. iphone在调试模式下释放内存但不在释放模式下
- 8. “双精度浮点格式”有多精确?
- 9. 浮点和双精度恒定比较
- 10. 将双精度转换为浮点数
- 11. Objective-C浮点数/双精度
- 12. 标准双精度IEEE浮点数有多少位的精度?
- 13. 专门为双精度和浮点精度的java类
- 14. 单精度大端浮点值到Python浮点数(双精度,大端)
- 15. 浮点精度
- 16. AdaGide:调试模式和释放模式
- 17. 作为两个双打总和的双双精度浮点数
- 18. 是否有可能以保真度将浮点双精度浮点双精度到两个十进制整数?
- 19. 浮法arithemtic和双精度?
- 20. 无法在Scala中写入双精度浮点和双精度浮点数的方法
- 21. 双精度浮点格式的最大和最小指数
- 22. 双精度浮标的双精度数字
- 23. FIT测试中的浮点精度
- 24. C++浮点精度
- 25. 与浮点精度
- 26. haskell浮点精度
- 27. XMLSerialization浮点精度
- 28. python中的浮点精度
- 29. 如何释放模式调试
- 30. 不同的行为调试vs释放模式android-释放模式冻结
你为什么认为他们不同? – 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