C#中的某些内容能否在运行时改变浮点比较行为?[x64]

C#中的某些内容能否在运行时改变浮点比较行为?[x64],c#,.net,C#,.net,我在Windows7 64位下的一个商业产品中遇到了一个非常奇怪的问题,VS2012.NET4.5编译为64位 在单独的项目中执行以下测试代码时,其行为符合预期(使用NUnit测试运行程序): 没有我得到的整个boostrap链(测试通过) 使用我获得的完整引导链(测试失败) 注意事项:浮点。ε在尾数中失去了最后一位 我看不到C++中的/FP编译器标志如何影响浮点。ε表示。< /P> 编辑和最终裁决 虽然可以使用单独的线程来获得float.Epsilon,但在FPU字减少的线程上,它的行为将不

我在Windows7 64位下的一个商业产品中遇到了一个非常奇怪的问题,VS2012.NET4.5编译为64位

在单独的项目中执行以下测试代码时,其行为符合预期(使用NUnit测试运行程序):

没有我得到的整个boostrap链(测试通过)

使用我获得的完整引导链(测试失败)

注意事项:浮点。ε在尾数中失去了最后一位

<>我看不到C++中的/FP编译器标志如何影响浮点。ε表示。< /P>
编辑和最终裁决 虽然可以使用单独的线程来获得float.Epsilon,但在FPU字减少的线程上,它的行为将不同于预期

在简化的FPU字线程上,这是“线程外来”float.Epsilon的输出

0: Sign: 0 (+)
   Exponent: 0xFFFFFF82 (-126)
   Mantissa: 0x0000000000001
请注意,最后一个尾数位如预期的那样为1,但此浮点值仍将被解释为0。这当然是有道理的,因为我们使用的浮点精度比FPU单词集更高,但对某些人来说可能是个陷阱


我决定移动到一台机器fps,该机器按这里所述计算一次:(当然是移植到float)

当我创建一个包含测试的测试应用程序时,不会抛出异常。这意味着它不会是简单的。需要进一步调查的一些想法:

  • 如果在应用程序开始时运行此测试(例如,在主/输入例程中),它是否失败
  • 如果上述情况属实,则使用运行相同测试的相同目标框架和体系结构启动一个新项目。如果它通过了,开始逐步添加主应用程序的位,看看是否可以找到导致它失败的位

如果在调试时和在发布模式下运行时出现差异,则可能会违反以下规定:

(自第12.1.3节起):

浮点数(静态、数组元素和类字段)的存储位置大小固定。。。其他地方(在计算堆栈上,作为参数,作为 返回类型和作为局部变量)浮点数使用内部浮点数表示 键入。。。它的 值可以用额外的范围和/或精度在内部表示

以及

当浮点值的内部表示形式的范围和/或精度大于其标称值时 类型放入存储位置时,它会自动强制为存储位置的类型。这可能涉及 精度损失或创建超出范围的值

最后一点是:

[注:使用比
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