代码之家  ›  专栏  ›  技术社区  ›  stack_pointer is EXTINCT

比较c中的双值#

  •  54
  • stack_pointer is EXTINCT  · 技术社区  · 16 年前

    我有一个 double 变量称为 x . 在代码中, X 得到一个值 0.1 我在“if”语句中检查它比较 X 零点一

    if (x==0.1)
    {
    ----
    }
    

    不幸的是,它没有进入 if 陈述

    1. 我应该用吗? Double 双重的 ?

    2. 这背后的原因是什么?你能为这个建议一个解决方案吗?

    15 回复  |  直到 6 年前
        1
  •  82
  •   Vadim Ovchinnikov    7 年前

    由于计算机如何存储浮点值,这是一个标准问题。在这里搜索“浮点问题”,你会发现大量的信息。

    简言之,“浮点数/双点数不能存储 0.1 准确地说。它总是会有一点偏离。

    您可以尝试使用 decimal 以十进制表示法存储数字的类型。因此 零点一 将准确地代表。


    你想知道原因:

    float/double存储为二进制分数,而不是十进制分数。举例说明:

    12.34 在十进制记数法中(我们所用的)是指

    1 * 101 + 2 * 100 + 3 * 10-1 + 4 * 10-2

    计算机以同样的方式存储浮点数,除了使用基数 2 以下内容: 10.01 方法

    1 * 21 + 0 * 20 + 0 * 2-1 + 1 * 2-2

    现在,您可能知道有些数字不能用十进制表示法完全表示。例如, 1/3 以十进制表示的是 0.3333333… .同样的事情也发生在二进制记数法中,只是不能精确表示的数字是不同的。其中是号码 1/10 . 用二进制表示法 0.000110011001100… .

    由于二进制表示法不能精确地存储它,所以它是以四舍五入的方式存储的。因此你的问题。

        2
  •  34
  •   Ohad Schneider    11 年前

    double Double 是一样的( 双重的 是的别名 )可以互换使用。

    将double与另一个值进行比较的问题是double是近似值,而不是精确值。所以当你设定 x 0.1 实际上,它可以存储为 0.100000001 或者类似的。

    您应该检查差异是否小于定义的最小差异(公差),而不是检查是否相等。比如:

    if (Math.Abs(x - 0.1) < 0.0000001)
    {
        ...
    }
    
        3
  •  15
  •   Valentin Kuzub    14 年前

    你需要结合 Math.Abs X-Y 和A value 与…相比。

    您可以使用以下扩展方法

    public static class DoubleExtensions
        {
            const double _3 = 0.001;
            const double _4 = 0.0001;
            const double _5 = 0.00001;
            const double _6 = 0.000001;
            const double _7 = 0.0000001;
    
            public static bool Equals3DigitPrecision(this double left, double right)
            {
                return Math.Abs(left - right) < _3;
            }
    
            public static bool Equals4DigitPrecision(this double left, double right)
            {
                return Math.Abs(left - right) < _4;
            }
    
            ...
    

    因为很少在double上调用方法,除了 ToString 我相信这是相当安全的扩展。

    然后你可以比较 x y 喜欢

    if(x.Equals4DigitPrecision(y))

        4
  •  10
  •   sharptooth    16 年前

    由于四舍五入的原因,比较浮点数并不总是能够精确地完成。比较

    (x == .1)
    

    计算机真的比较

    (x - .1) vs 0
    

    由于浮点数在机器上的表示方式不同,因此不能精确地重新表示模拟结果。因此,得到一些非零值,条件的计算结果为 false .

    克服这种比较

    Math.Abs(x- .1) vs some very small threshold ( like 1E-9)
    
        5
  •  5
  •   Alfred Myers    16 年前

    documentation :

    比较的精确度 应谨慎使用equals方法,因为由于两个值的精度不同,两个明显等效的值可能不相等。下面的示例报告double值.3333和用1除以3返回的double不相等。

    一种建议的方法不是比较相等,而是定义两个值之间可接受的差异幅度(例如其中一个值的0.01%)。如果两个值之间的差值的绝对值小于或等于该差值,则该差值可能是由于精度差异造成的,因此,这些值可能是相等的。下面的示例使用此技术比较.33333和1/3,前一个代码示例发现的两个不相等的双精度值。

    因此,如果您真的需要双人间,您应该使用文档中描述的技术。 如果可以,将其更改为十进制。 会慢一点 但是你不会遇到这种问题。

        6
  •  3
  •   Hans Kesting    16 年前

    double和double是相同的。

    为此,请参见 http://www.yoda.arachsys.com/csharp/floatingpoint.html . 简言之:“double”不是一个精确的类型,“x”和“0.1”之间的细微差别会使它消失。

        7
  •  3
  •   user151323    16 年前

    由于舍入和内部表示问题,浮点值的精确比较并不总是有效。

    尝试不精确的比较:

    if (x >= 0.099 && x <= 0.101)
    {
    }
    

    另一种选择是使用十进制数据类型。

        8
  •  2
  •   Svetlozar Angelov    16 年前

    使用 decimal . 它没有这个“问题”。

        9
  •  2
  •   Nicole Tedesco    8 年前

    从Java代码库中获取提示,尝试使用 .CompareTo 并测试零比较。这假设 .比较 函数以精确的方式考虑浮点相等。例如,

    System.Math.PI.CompareTo(System.Math.PI) == 0
    

    此谓词应返回 true .

        10
  •  1
  •   Lars Corneliussen    16 年前

    1)我应该用双份还是双份?你说什么?

    Double double 是一样的。 双重的 只是一个C关键字作为类的别名 System.Double 最常见的是使用别名!同样的 string ( System.String ) int ( System.Int32 )

    也看到 Built-In Types Table (C# Reference)

        11
  •  1
  •   Timothy Walters    16 年前

    double(在某些语言中称为float)由于舍入问题而充满问题,只有在需要近似值时才是好的。

    decimal数据类型执行所需的操作。

    因为引用decimal和decimal在.NET C中是相同的,double和double类型也是相同的,它们都引用相同的类型(如您所见,decimal和double非常不同)。

    请注意,decimal数据类型有一些相关的成本,因此在查看循环等时要小心使用它。

        12
  •  0
  •   Jorge Córdoba    16 年前

    一般来说:

    在大多数情况下,双重表示已经足够好了,但在某些情况下可能会惨遭失败。如果需要完全精确(如在财务应用程序中),请使用十进制值。

    双精度数的大多数问题不是直接比较的结果,它通常是几个数学运算的累积结果,这些运算由于舍入和分数错误(尤其是乘法和除法)而以指数形式干扰值。

    如果代码是:

    x = 0.1
    
    if (x == 0.1)
    

    它不应该失败,这是简单的失败,如果x值是通过更复杂的方法或操作计算出来的,那么调试器使用的toString方法很有可能使用智能舍入,也许您也可以这样做(如果风险太大,请返回使用小数):

    if (x.ToString() == "0.1")
    
        13
  •  0
  •   Ahmed Fwela    8 年前

    我发现一个很酷的方法就是 .GetHashCode() 方法,返回表示double的int,即

    (0.4d + 0.3d + 0.2d + 0.1d).GetHashCode() //returns -1072693248

    1d.GetHashCode() //returns 1072693248

    如你所说,现在我们可以用这样的东西

    public static bool AccurateEquality(double first,double second)
    {
        return Math.Abs(first.GetHashCode()) == Math.Abs(second.GetHashCode());
    }
    

    用法: AccurateEquality((0.4d + 0.3d + 0.2d + 0.1d),1) //returns true

    而: (0.4d + 0.3d + 0.2d + 0.1d) == 1d //returns false

    我在多个案例中都试过,而且效果很好。

        14
  •  0
  •   Freesnöw    6 年前

    浮点数表示法是众所周知的不准确(因为浮点数在内部存储的方式),例如x实际上可能是0.0999999999或0.10000001,并且您的条件将失败。如果您想确定浮点数是否相等,您需要具体说明它们是否在某个公差范围内相等。

    if(Math.Abs(x) - 0.1 < tol) {
       // Do something 
    }
    
        15
  •  -7
  •   Ehsan Mohammadi    9 年前

    大多数以上的方法或遵循愚蠢的扩展方法!

    public static bool EqualsTo(this double value, double value2)
    {
        var bytes1 = BitConverter.GetBytes(value);
        var bytes2 = BitConverter.GetBytes(value2);
    
        var long1 = BitConverter.ToInt64(bytes1, 0);
        var long2 = BitConverter.ToInt64(bytes2, 0);
    
        return long1 == long2;
    }
    
    推荐文章