为什么我在调试和发布模式之间出现算术差异,我该如何解决它们?

Chr*_*sJJ 4 visual-studio-2010 c#-4.0

在我的程序中这个片段:

  trace.log(
   String.Format("a= {0:R} b= {1:R} a<b= {2}", 
    b.GetPixel(447, 517).GetBrightness(), (100F / 255F),
    b.GetPixel(447, 517).GetBrightness() < (100F / 255F))
  );
Run Code Online (Sandbox Code Playgroud)

在Debug\prog.exe中输出:

 a= 0.392156869 b= 0.392156869 a<b= False
Run Code Online (Sandbox Code Playgroud)

但这在Release\prog.exe中有不同的结果:

 a= 0.392156869 b= 0.392156869 a<b= True
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释为什么相同的操作数给出不同的比较结果?并建议一个补救措施,理想的程序范围,如编译器开关?谢谢.

编辑:澄清:以上结果来自在Windows资源管理器中启动Debug\prog.exe和Release\prog.exe.

编辑:更多信息:从VS执行,"开始调试"给出False(即准确的结果,与WE启动的Debug\prog.exe相同),"Start without debugging"给出True(即不准确的结果,与WE相同) - 发布Release\prog.exe.

编辑:替换文字替代的替代测试用例

这两个案例

  trace.log(
   String.Format("a= {0:R} b= {1:R} a<b= {2}",
    0.392156869F, 0.392156869F, 
    0.392156869F < 0.392156869F)
  );
  trace.log(
   String.Format("a= {0:R} b= {1:R} a<b= {2}",
    0.392156869F, (100F / 255F),
    0.392156869F < (100F / 255F))
  );
Run Code Online (Sandbox Code Playgroud)

显示Debug和Release输出中没有差异.这个案例:

  trace.log(
   String.Format("a= {0:R} b= {1:R} a<b= {2}",
    b.GetPixel(447, 517).GetBrightness(), 0.392156869F,
    b.GetPixel(447, 517).GetBrightness() < 0.392156869F)
  );
Run Code Online (Sandbox Code Playgroud)

显示与原始测试用例相同的差异(以及Release中的不准确性).

编辑:姗姗来迟的最小测试案例演示问题

Color c = Color.FromArgb( 255, 100, 100, 100 );
trace.log(
 String.Format("a= {0} b= {1} a<b= {2}",
 c.GetBrightness(), 0.392156869F,
 c.GetBrightness() < 0.392156869F)
);
Run Code Online (Sandbox Code Playgroud)

在Debug\prog.exe中输出此正确的结果:

 a= 0.392156869 b= 0.392156869 a<b= False
Run Code Online (Sandbox Code Playgroud)

但是Release\prog.exe中的这个错误结果:

 a= 0.392156869 b= 0.392156869 a<b= True
Run Code Online (Sandbox Code Playgroud)

编辑:补救措施

1)来自Peter的答案如下:

trace.log(
 String.Format("a= {0:R} b= {1:R} a<b= {2}",
  c.GetBrightness(), 0.392156869F, 
  c.GetBrightness().CompareTo(0.392156869F)<0)
);
Run Code Online (Sandbox Code Playgroud)

2)来自ChrisJJ,提问者(更新):

float comp = c.GetBrightness();
trace.log(
 String.Format("a= {0:R} b= {1:R} a<b= {2}", 
 comp, 0.392156869F,
 comp < 0.392156869F)
);
Run Code Online (Sandbox Code Playgroud)

我认为这增加了发布模式编译器错误的证据.

Pet*_* O. 7

它很可能是调试模式和发布模式之间不同浮点规则的结果(参见此处此处).

更新:

感谢您对该问题的新更新,我能够在我的机器(64位Windows)上重现该问题.这似乎只有在将平台设置为X86时才会发生; X64和AnyCPU平台在发布模式下显示正确的结果.可能,当平台是X86时,公共语言运行库在64位计算机中应用X86仿真,并且显然在比较运算符中混乱.

但是,我发现了一种可能的解决方法:使用CompareTo而不是"<"和">"运算符,如下所示:

c.GetBrightness().CompareTo(0.392156869F)<0
Run Code Online (Sandbox Code Playgroud)

在我的机器上,这将在X86和X64和AnyCPU中提供相同的正确结果.