C#中的某些内容能否在运行时改变浮点比较行为?[x64]
我在Windows7 64位下的一个商业产品中遇到了一个非常奇怪的问题,VS2012.NET4.5编译为64位 在单独的项目中执行以下测试代码时,其行为符合预期(使用NUnit测试运行程序): 没有我得到的整个boostrap链(测试通过) 使用我获得的完整引导链(测试失败) 注意事项:浮点。ε在尾数中失去了最后一位 <>我看不到C++中的/FP编译器标志如何影响浮点。ε表示。< /P>C#中的某些内容能否在运行时改变浮点比较行为?[x64],c#,.net,C#,.net,我在Windows7 64位下的一个商业产品中遇到了一个非常奇怪的问题,VS2012.NET4.5编译为64位 在单独的项目中执行以下测试代码时,其行为符合预期(使用NUnit测试运行程序): 没有我得到的整个boostrap链(测试通过) 使用我获得的完整引导链(测试失败) 注意事项:浮点。ε在尾数中失去了最后一位 我看不到C++中的/FP编译器标志如何影响浮点。ε表示。< /P> 编辑和最终裁决 虽然可以使用单独的线程来获得float.Epsilon,但在FPU字减少的线程上,它的行为将不
编辑和最终裁决 虽然可以使用单独的线程来获得float.Epsilon,但在FPU字减少的线程上,它的行为将不同于预期 在简化的FPU字线程上,这是“线程外来”float.Epsilon的输出
0: Sign: 0 (+)
Exponent: 0xFFFFFF82 (-126)
Mantissa: 0x0000000000001
请注意,最后一个尾数位如预期的那样为1,但此浮点值仍将被解释为0。这当然是有道理的,因为我们使用的浮点精度比FPU单词集更高,但对某些人来说可能是个陷阱
我决定移动到一台机器fps,该机器按这里所述计算一次:(当然是移植到float)当我创建一个包含测试的测试应用程序时,不会抛出异常。这意味着它不会是简单的。需要进一步调查的一些想法:
- 如果在应用程序开始时运行此测试(例如,在主/输入例程中),它是否失败
- 如果上述情况属实,则使用运行相同测试的相同目标框架和体系结构启动一个新项目。如果它通过了,开始逐步添加主应用程序的位,看看是否可以找到导致它失败的位
float32
或float64
更宽的内部表示可能会导致
计算结果当开发人员对其代码进行看似无关的修改时
这可能是一个值从内部表示(例如,在寄存器中)溢出到
堆栈。结束注释]
调试通常会导致大量修改-您倾向于使用不同的优化,并且更可能导致此类溢出。DirectX会修改FPU设置。见这一相关问题:
调用
CreateDevice
时,您可以通过指定D3DCREATE\u FPU\u preserve
标志来告诉DirectX保留FPU设置,或者在新线程上执行浮点代码。听起来很像(编译器的)优化错误。您是否使用任何优化标志?请参阅“舍入模式”,您的设置代码使用DirectX的哪些链接?这可能会影响FPU设置:我看不出C++中的/FP编译器标志如何影响浮点。您询问代码是否可以更改浮点数的行为。/fp文档链接到一个页面,该页面显示如何更改浮点控制字,使程序能够更改浮点数学包中的精度、舍入和无限模式,具体取决于平台。您可以修改设置代码以设置D3DCREATE_FPU_PRESERVE吗?或者,您可以在一个新线程上执行有问题的代码吗?两次运行都处于调试状态,没有打开“Optimize code”标志,我试图区分它的fpu设置是否在本机部分。Direct x,您描述的调试问题,或在64位上下文中的64位计算机上使用32位浮点。给定这两种方法都不可行(保留FPU或在另一个线程中执行所有测试)我想知道一个合适的解决方案是像中那样计算机器的相对epsilon,还是尝试从从从另一个线程获取它的utils函数中获取float.epsilon(我已经测试过:)
if ((x * x + y * y + z * z) <= (float.Epsilon)) // this works!
if ((x * x + y * y + z * z) < (float.Epsilon*10)) // this doesn't!
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
var res = (x*x + y*y + z*z);
Console.WriteLine(GetComponentParts(res));
Console.WriteLine();
Console.WriteLine(GetComponentParts(float.Epsilon));
0: Sign: 0 (+)
Exponent: 0xFFFFFF82 (-126)
Mantissa: 0x0000000000000
1.401298E-45: Sign: 0 (+)
Exponent: 0xFFFFFF82 (-126)
Mantissa: 0x0000000000001
0: Sign: 0 (+)
Exponent: 0xFFFFFF82 (-126)
Mantissa: 0x0000000000000
0: Sign: 0 (+)
Exponent: 0xFFFFFF82 (-126)
Mantissa: 0x0000000000000
0: Sign: 0 (+)
Exponent: 0xFFFFFF82 (-126)
Mantissa: 0x0000000000001