比较C#中的double值

sta*_*NCT 59 .net c# double

我有一个double名为的变量x.在代码中,x获取一个值,0.1我在'if'语句中检查它,比较x0.1

if (x==0.1)
{
----
}
Run Code Online (Sandbox Code Playgroud)

不幸的是它没有进入if声明

  1. 我应该使用Doubledouble

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

Vil*_*lx- 92

由于计算机存储浮点值的方式,这是一个标准问题.在这里搜索"浮点问题",你会发现大量的信息.

简而言之 - 浮动/双重不能0.1精确存储.它总会有点偏差.

您可以尝试使用decimal以十进制表示法存储数字的类型.这样0.1就可以准确表达.


你想知道原因:

浮点/双精度存储为二进制分数,而非十进制分数.为了显示:

12.34 十进制表示法(我们使用的)表示

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

计算机以相同的方式存储浮点数,除了它使用base 2:10.01means

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

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

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

  • 我完全理解你上面说的话.但是,为什么,如果他写了`x = 0.01;`指定`x`然后与文字'0.01'进行比较,那么`x`和'0.01`的实际基础二进制值不会相同(再次,假设没有使用计算来指定"x").因此,`(x == 0.01)`应该工作,不是吗?一旦你用'x`执行一些算术,所有的赌注都会关闭.另外,我会更明确地说:`if(x == 0.01d)`明确声明`0.01`是一个double(而不是将`0.01`从`float`转换为`double`) - 这可能一直是个问题. (15认同)
  • 是的,如果你做`x = 0.01; if(x == 0.01)`那么比较应该是真的.好吧,假设没有任何隐式的float-to-double数据类型转换(尽管可能就是这样).但OP没有具体说明他是如何获得第一个"0.01"的.它很可能来自计算. (3认同)

Run*_*tad 41

double并且Double是相同的(double是别名Double),可以互换使用.

将double与另一个值进行比较的问题是,double是近似值,而不是精确值.因此,当你设置它时x,0.1它实际上可能存储为0.100000001或类似的东西.

您应该检查差异是否小于定义的最小差异(容差),而不是检查是否相等.就像是:

if (Math.Abs(x - 0.1) < 0.0000001)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)


Val*_*zub 19

你需要一个Math.Abson X-Y和a 的组合value来比较.

您可以使用以下Extension方法

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;
        }

        ...
Run Code Online (Sandbox Code Playgroud)

因为你很少在double上调用方法,除非ToString我相信它非常安全的扩展.

然后你可以比较xy喜欢

if(x.Equals4DigitPrecision(y))


sha*_*oth 10

由于四舍五入,因此不能总是精确地比较浮点数.比较

(x == .1)
Run Code Online (Sandbox Code Playgroud)

电脑真的比较

(x - .1) vs 0
Run Code Online (Sandbox Code Playgroud)

由于机器上如何表示浮点数,因此无法始终精确地表示缩减结果.因此,您获得一些非零值并且条件评估为false.

为了克服这种比较

Math.Abs(x- .1) vs some very small threshold ( like 1E-9)
Run Code Online (Sandbox Code Playgroud)


Sve*_*lov 5

使用decimal。它不存在这个“问题”。

  • 十进制值的运算要慢得多。我们不应该仅仅因为“没有这个问题”就总是使用十进制类型。两种类型都有自己的用途。 (11认同)

Alf*_*ers 5

文档:

比较精度应谨慎使用Equals方法,因为两个明显等效的值可能不相等,因为这两个值的精度不同.以下示例报告Double值.3333和通过除以1而返回的Double是不相等的.

...

一种推荐的技术不是比较相等性,而是涉及在两个值之间定义可接受的差异裕度(例如其中一个值的0.01%).如果两个值之间的差的绝对值小于或等于该边界,则差异可能是由于精度的差异,因此,值可能相等.以下示例使用此技术比较.33333和1/3,前两个代码示例发现的两个Double值不相等.

因此,如果您确实需要双倍,则应使用文档中描述的技术.如果可以,请将其更改为小数.它会慢一点,但你不会遇到这类问题.