简单表达式中的意外结果

Unexpected result in a simple expression

我正在使用 .Net Framework 4.7.2 创建一个简单的数学函数来比较两个数字

原来的功能是这个

public static bool AreNumbersEquals(float number, float originalNumber, float threshold) => 
(number >= originalNumber - threshold) && (number <= originalNumber + threshold);

但令我惊讶的是,当我使用此语句对其进行测试时

var result = AreNumbersEquals(4.14f, 4.15f, 0.01f);

返回值为false

所以我用这段代码拆分了函数

namespace ConsoleApp1_netFramework
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var qq = AreNumbersEquals(4.14f, 4.15f, 0.01f);
        }

        public static bool AreNumbersEquals(float number, float originalNumber, float threshold)
        {
            var min = originalNumber - threshold;
            var max = originalNumber + threshold;
            var minComparisson = number >= min;
            var maxComparisson = number <= max;

            // result1 is true (as expected)
            var result1 = minComparisson && maxComparisson;

            // result2 is false (why?)
            var result2 = number >= originalNumber - threshold && number <= originalNumber + threshold;

            return result2;
        }
    }
}

现在 result1true 正如预期的那样,但是 result2false

谁能解释一下?

更新 1: 我了解 CPU 级别的浮点数和算术运算方式。我对这种特殊情况很感兴趣,因为在高层次上计算是相同的,所以我希望两种写比较的方式都能得到相同的结果。

我目前正在做的项目是一个游戏所以doubledecimal由于性能问题尽可能避免涉及算术计算的惩罚。

更新 2: 为 64 位架构编译时,条件 returns 为真,但为 32 位架构编译时,条件 returns 为假。

Can anyone explain this?

是的。对于 result1,您将中间结果分配给 float 变量,这会强制它返回 32 位——可能会截断结果。 (由于这些是局部变量,结果可能可能不会被截断。这部分的规范很棘手。)

对于 result2,您正在执行“内联”比较,这允许所有算术和比较以更高的精度完成,可能会改变结果。

从根本上说,4.14f、4.15f 和 0.01f 不是 恰好是 4.14、4.15 和 0.01...所以任何假设它们的东西都可能有一些微妙的问题.这些浮点文字的精确值为:

  • 4.139999866485595703125
  • 4.150000095367431640625
  • 0.00999999977648258209228515625

如您所见,如果您使用这些值手动计算,您确实会发现该数字超出了阈值。正是中间值的精度损失使您的第一次测试有所不同。