2012-08-07 97 views
1

我在一个应用程序中有一个相当奇怪的错误,我设法缩小到这个简单的测试用例。布尔值在调试模式下比在发布模式下有所不同

protected void Page_Load(object sender, EventArgs e) 
{ 
    bool isHeightExceeded = IsHeightExceeded(10.16f, 127.15f); 
    lit.Text = isHeightExceeded.ToString(); 
} 

private bool IsHeightExceeded(float y, float height) 
{ 
    float nextHeight = y + height; 
    return (137.31f - nextHeight) < 0; 
} 

当我构建和调试模式下运行这个isHeightExceeded布尔是假的(如我所期望的),但是当我重建和在释放模式运行,现在是真。

幕后发生了什么事情?我猜测它与浮点精度有关,但不完全确定它是什么。

任何帮助,将不胜感激。

+2

试图清理并重建您的解决方案? – 2012-08-07 10:26:08

+0

打印结果137.31f - nextHeight并检查。 – 2012-08-07 10:29:33

+0

与优化发布版本中的代码有关的事情可以优化计算结果,但通过无法做到这一点的调试步骤,也许呢? – podiluska 2012-08-07 10:31:15

回答

4

我怀疑在64位(或80位)计算10.16f + 127.15f的值,然后与137.31f进行比较......然而在释放模式下计算该值,然后截断为32位,然后再截断为相比。基本上,当中间值不被钳位到更小的精度时,您可以得到像这样的结果。

如果这是一个问题,即可能意味着你不应该使用floatdouble入手 - 如果这些意思是精确值,使用decimal代替。

+0

谢谢,这是有道理的,听起来可能是这样 - 更改为小数可以给出正确的结果。 – 2012-08-07 11:33:54

1

10.16 + 127.15正好等于137.31,这意味着(137.31f - nextHeight)理论值为0

由于有参与数值运算,你可以在一个数值精度问题承担。使用调试器时可能会以不同的方式处理此问题。这只是一个猜想,但我不会感到惊讶。

在任何情况下,您的代码都需要更正以解决精确度错误,并使用自定义公差值(例如0.00001)来获得可预测的结果给读者和用户。如果您不添加该容差,则该代码可以正确工作,仅用于双精度值,而不用于读取它的人员。

+2

区别在于比Single.Epsilon更大。 '137.31f - nextHeight'产生'-3,814697265625E-06',而'Single.Epsilon'为'1,401298E-45'。 epsilon的使用在这里不会起到帮助作用,尽管这是一个很好的建议。 – 2012-08-07 10:33:49

+0

@DanielHilgarth我在想一个“手工制作”的epsilon,而不是Single.Epsilon。在我的生产代码中,我使用这些手工制作的ε值通常为1E-5或1E-6。我会编辑我的答案以避免混淆。 – 2012-08-07 10:35:42

相关问题