简单表达式中的意外结果
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;
}
}
}
现在 result1 是 true 正如预期的那样,但是 result2 是 false
谁能解释一下?
更新 1: 我了解 CPU 级别的浮点数和算术运算方式。我对这种特殊情况很感兴趣,因为在高层次上计算是相同的,所以我希望两种写比较的方式都能得到相同的结果。
我目前正在做的项目是一个游戏所以double和decimal由于性能问题尽可能避免涉及算术计算的惩罚。
更新 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
如您所见,如果您使用这些值手动计算,您确实会发现该数字超出了阈值。正是中间值的精度损失使您的第一次测试有所不同。
我正在使用 .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;
}
}
}
现在 result1 是 true 正如预期的那样,但是 result2 是 false
谁能解释一下?
更新 1: 我了解 CPU 级别的浮点数和算术运算方式。我对这种特殊情况很感兴趣,因为在高层次上计算是相同的,所以我希望两种写比较的方式都能得到相同的结果。
我目前正在做的项目是一个游戏所以double和decimal由于性能问题尽可能避免涉及算术计算的惩罚。
更新 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
如您所见,如果您使用这些值手动计算,您确实会发现该数字超出了阈值。正是中间值的精度损失使您的第一次测试有所不同。