我一直在尝试解决由浮点运算引起的错误,并将其简化为一段导致我不理解的行为的简单代码:
float one = 1;
float three = 3;
float result = one / three;
Console.WriteLine(result); // prints 0.33333
double back = three * result;
if (back > 1.0)
Console.WriteLine("larger than one");
else if (back < 1.0)
Console.WriteLine("less than one");
else
Console.WriteLine("exactly one");
结果四舍五入为 0.33333,我希望返回小于 1,但输出“大于 1”。
有人可以解释这里发生了什么吗?
最佳答案
使用 IEEE 754 舍入,让我们看看发生了什么。
在 IEEE 754 单精度浮点中,有限数的值由以下内容决定:
-1sign × 2exponent × (1 + mantissa × 2-23)
在哪里
如果我们用 0 代替符号,用 -2 代替指数,那么我们可以保证一个介于 0.25 和 0.5 之间的值。为什么?
1 × 2-2
是 ¼。的值(value)
1 + mantissa × 2-23
保证在 1 和 2 之间,所以这是我们的符号和指数排序。
继续前进,我们可以很快得出有两个值可以用作尾数值:2796202 和 2796203。
将每一个代入,我们得到以下两个值(一个较低,一个较高):
精确值(最多 22 位)的二进制表示为:
1010101010101010101010...
因为下一个数字是
1
,这意味着值向上取整,而不是向下取整。出于这个原因,较高的错误比较低的错误更小:而且由于它大于精确值,因此当乘回它时,它将大于 1。这就是为什么它使用一个最初出现的值——二进制舍入有时与十进制舍入的方向相反。
关于C# 浮点舍入行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21795283/