双值在C#中的比较

问题描述 投票:57回答:15

我已经叫double一个x变量。在代码中,x被分配0.1的价值,我检查它在“如果”语句比较x0.1

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

遗憾的是它并没有进入if声明

  1. 我应该使用Doubledouble
  2. 什么是这背后的原因是什么?你能提出一个解决方案?
c# .net double
15个回答
92
投票

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

简而言之 - 一个浮点/双精度不能精确存储0.1。它总是会有点偏离。

您可以尝试使用存储十进制数的decimal类型。因此0.1会表示的精确。


你想知道其中的原因:

浮动/双存储为二进制小数,而不是小数。为了显示:

12.34十进制(我们使用的)手段

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

计算机存储浮点数以相同的方式,除了使用碱210.01装置

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

现在,你可能知道,有一些数字,不能与我们的十进制表示充分体现。例如,在1/3十进制表示法是0.3333333…。同样的事情发生在二进制表示法,但不能精确代表的数字是不同的。其中之一是数字1/10。在二进制表示法是0.000110011001100…

由于二进制码不能存储它,确切地说,它是存储在四舍五入的方式。因此,你的问题。


1
投票

双(称为浮在某些语言)是fraut与由于四舍五入问题的问题,这是唯一的好,如果你需要的近似值。

十进制数据类型你想要做什么。

仅供参考小数和十进制是在.NET C#一样的,都是双和Double类型,它们都指的是同一类型(十进制和双有很大的不同,虽然,因为你已经看到了)。

要注意的是十进制数据类型有与之相关的一些费用,所以如果你正在寻找循环等谨慎使用


1
投票

从Java代码库以尖端,尝试使用.CompareTo和测试用于零比较。这假定.CompareTo函数以以考虑浮点平等以精确的方式。例如,

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

这个谓词应该返回true


0
投票

作为基本规则:

双表示是在大多数情况下不够好,但可能在某些情况下惨遭失败。如果你需要完整的精度(如在财务应用程序)使用十进制值。

大多数问题与双打不是来自直接比较,用它来有几个数学运算这极大值打扰由于四舍五入和分数误差(尤其是乘法和除法)积累的结果。

检查你的逻辑,如果代码是:

x = 0.1

if (x == 0.1)

它不应该失败,这是简单的失败,如果X值是通过更复杂的手段或操作它很可能调试器所使用的ToString方法是使用智能四舍五入,也许你可以这样做(如果那是太冒险去计算回使用十进制):

if (x.ToString() == "0.1")

0
投票

浮点数表示是众所周知的不准确的(因为浮体内部存储的方式),例如X实际上可能是0.0999999999或0.100000001,你的状态将会失败。如果要确定是否花车等于你需要具体他们是否是等于容许的范围内。

if(Math.Abs(x) - 0.1 < tol) {
   // Do something 
}

0
投票
// number of digits to be compared    
public int n = 12 
// n+1 because b/a tends to 1 with n leading digits
public double Epsilon { get; } = Math.Pow(10, -(n+1)); 

public bool IsEqual(double a, double b)
{
    if (Math.Abs(a)<= double.Epsilon || Math.Abs(b) <= double.Epsilon)
        return Math.Abs(a - b) <=  double.Epsilon;
    return Math.Abs(1.0 - a / b) <=  Epsilon;
}

39
投票

doubleDouble是相同的(double是一个别名Double),可以互换使用。

与比较双与另一个值的问题是,双打是近似值,而不是精确值。所以,当你设置x0.1可能在现实中被存储为0.100000001或类似的东西。

不是检查平等的,你应该检查差小于规定的最小差值(宽容)。就像是:

if (Math.Abs(x - 0.1) < 0.0000001)
{
    ...
}

19
投票

你需要Math.AbsX-Y组合和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;
        }

        ...

因为你很少打电话双方法除了ToString我相信它非常安全的扩展。

然后,你可以比较xy

if(x.Equals4DigitPrecision(y))


10
投票

比较浮点数不能总是精确地完成,因为四舍五入的。比较

(x == .1)

电脑真正比较

(x - .1) vs 0

sybtraction的结果不能总是精确represeted因为浮点数是如何在机器上表示。因此,你得到一些非零值和条件计算结果为false

为了克服这个比较

Math.Abs(x- .1) vs some very small threshold ( like 1E-9)

5
投票

documentation

精度比较equals方法应谨慎由于这两个值的不同精度中使用,因为两个明显等效值可以是不相等的。下面的示例报告该双值0.3333以及双人用1除以3返回是不相等的。

...

而不是相等的比较,一个推荐的技术包括定义两个值之间的差值的一个可接受的裕度(如其中一个值的0.01%)。如果这两个值之间的差的绝对值小于或等于余量,差异很可能是由于在精度的差异,因此,该值可能是相等的。下面的示例使用此技术来比较0.33333和1/3,即前面的代码示例发现是不相等的两个双值。

所以,如果你真的需要一个双,你应该使用的文档描述的技术。如果可以的话,将其更改为十进制。这会慢一些,但你不会有这种类型的问题。


3
投票

双人和双是相同的。

至于原因,看http://www.yoda.arachsys.com/csharp/floatingpoint.html。简而言之:双重是不是一个确切的类型和“x”和“0.1”将抛出其关闭之间的微小差异。


3
投票

浮点值的精确比较知道并不总是由于舍入和内部表示问题开展工作。

尽量不准确的比较:

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

另一种方法是使用十进制数据类型。


2
投票

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


1
投票

1)我应该使用双人或双???

Doubledouble是同样的事情。 double只是一个C#的关键字作为别名类工作System.Double最常见的就是用别名!同为stringSystem.String),intSystem.Int32

另见Built-In Types Table (C# Reference)

© www.soinside.com 2019 - 2024. All rights reserved.