繁体   English   中英

C#浮点舍入行为

[英]C# floating point rounding behavior

我一直在尝试解决由浮点算术引起的错误,并将其简化为导致我不了解行为的简单代码:

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”。

有人可以解释这里发生了什么吗?

当我尝试上面的代码时,我发现

float result = one / three;

语句将result的值评估为0.333333343而不是0.33333但控制台将其打印为0.33333 ,然后执行以下语句

double back = three * result;

它将back评估为1.0000000298023224 ,显然大于1,这就是为什么您得到“大于1”的原因

使用IEEE 754取整,让我们看看发生了什么。

在IEEE 754单精度浮点中,有限数的值由以下各项决定:

-1 ×2 指数 ×(1 +尾数×2 -23

哪里

  • 如果为正,则符号为0,否则为1;
  • 指数是介于-126和127之间的值(-127和128是特殊值);
  • 尾数是介于0和8388607之间的值(因为它是23位整数)。

如果我们用0代替正负号 ,而用-2代替指数 ,那么我们保证数值在0.25和0.5之间。 为什么?

1×2 -2

是¼。 的价值

1 +尾数×2 -23

保证在1到2之间,所以这是我们的符号和指数排序。


继续前进,我们可以很快得出结论,可以将两个值用作数值:2796202和2796203。

将每个值替换为以下两个值(一个较低,一个较高):

  • 0.333333313465118408203125( 尾数 = 2796202)
  • 0.3333333432674674407958984375( 尾数 = 2796203)

精确值的二进制表示形式(最多22位)是:

1010101010101010101010...

由于下一位为1 ,这意味着该值将向上舍入不是向下舍入。 因此,较高的错误比较低的错误要小:

  • 0.333333313465118408203125-≑-1.987×10 -8
  • 0.3333333432674674958958984375-≑9.934×10 -9

而且由于它大于精确值,因此乘以后将大于1。这就是为什么它使用最初显示的值的原因-二进制舍入有时与十进制舍入相反。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM