C# 浮点舍入行为

标签 c# .net floating-point

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

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,否则为 1;
  • exponent 是介于 -126 和 127 之间的值(-127 和 128 是特殊的);和
  • 尾数是介于 0 和 8388607 之间的值(因为它是 23 位整数)。

  • 如果我们用 0 代替符号,用 -2 代替指数,那么我们可以保证一个介于 0.25 和 0.5 之间的值。为什么?

    1 × 2-2



    是 ¼。的值(value)

    1 + mantissa × 2-23



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

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

    将每一个代入,我们得到以下两个值(一个较低,一个较高):
  • 0.333333313465118408203125(尾数 = 2796202)
  • 0.3333333432674407958984375(尾数 = 2796203)

  • 精确值(最多 22 位)的二进制表示为:
    1010101010101010101010...
    

    因为下一个数字是 1 ,这意味着值向上取整,而不是向下取整。出于这个原因,较高的错误比较低的错误更小:
  • 0.333333313465118408203125 - ⅓ ≑ -1.987 × 10-8
  • 0.3333333432674407958984375 - ⅓ ≑ 9.934 × 10-9

  • 而且由于它大于精确值,因此当乘回它时,它将大于 1。这就是为什么它使用一个最初出现的值——二进制舍入有时与十进制舍入的方向相反。

    关于C# 浮点舍入行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21795283/

    相关文章:

    c# - 从 WCF 中的 HTTP 响应中删除服务器

    c# - 如何在 XNA 中旋转边界框?

    c# - 如何评估 C# 中可以被零除的字符串表达式?

    Java:三角函数和双重误差导致 NaN

    c# - 在 C# SQL 查询中,Parameters.Add() 比直接在查询中嵌入值有什么优势?

    .net - 如果单击复选框,则仅更改ListViewItem的“已检查”状态

    c# - 指定的强制类型转换无效 – SQL float to C# double

    c# - 如何在 Windows 窗体设计器中保存用户控件的结构属性?

    floating-point - Ada:常量声明

    java - Math.Ceil 的浮点精度 (Java)