代码之家  ›  专栏  ›  技术社区  ›  Imad

计算机是否已开始正确存储0.1?

  •  -3
  • Imad  · 技术社区  · 8 年前

    在学习浮点运算时,我遇到了一个问题,我引用了一句话:“float/double不能精确地存储0.1”。

    有一个 question 就这样指向同一件事并接受回答也是很有说服力的。但是我想在自己的电脑上试试,所以我写了如下程序

    double a = 0.1;
    
    if (a == 0.1)
    {
        Console.WriteLine("True");
    }
    else
    {
        Console.WriteLine("False");
    }
    
    Console.Read();
    

    和控制台打印 True 是的。令人震惊的是,我已经被其他事情说服了。有人能告诉我浮点运算是怎么回事吗?或者我刚买了一台电脑,把数值存储为基数10?

    1 回复  |  直到 8 年前
        1
  •  7
  •   Jon Skeet    8 年前

    您的程序只检查编译器是否以相同的方式逼近0.1,这是它所做的。

    价值 a 不是0.1,你没有检查它是否 0.1分。您正在检查“最接近0.1的可表示值”是否等于“最接近0.1的可表示值”。

    您的代码有效地编译为:

    double a = 0.1000000000000000055511151231257827021181583404541015625;
    
    if (a == 0.1000000000000000055511151231257827021181583404541015625)
    {
        Console.WriteLine("True");
    }
    else
    {
        Console.WriteLine("False");
    }
    

    …因为0.100000000000000551151231257827021181583404541015625是 double 最接近0.1的值。

    有时你还能看到一些非常奇怪的效果。当 双重的 定义为64位ieee-754数字,c规范允许中间表示使用更高的精度。这意味着,有时将一个值赋给一个字段的简单操作可能会改变结果,甚至可以转换一个已经存在的值 双重的 双重的 是的。

    在你提到的问题中,我们不知道原值是如何获得的。问题是:

    我有一个双变量 x .在密码里, 获取分配的值0.1。

    我们不知道它是如何被赋值为0.1的,这个细节很重要。我们知道价值不会 确切地 0.1,什么样的近似已经被涉及?例如,请考虑以下代码:

    using System;
    
    class Program
    {
        static void Main()
        {
            SubtractAndCompare(0.3, 0.2);
        }
    
        static void SubtractAndCompare(double a, double b)
        {
            double x = a - b;
            Console.WriteLine(x == 0.1);
        }
    }
    

    价值 大约是0.1,但它与“最接近的 双重的 值为0.1“。在这种情况下,它恰好略小于0.1-该值正好是0.099999999999777955395074968691527366818359375,这不等于0.10000000000000055115123125782702118158340451015625…所以比较结果是假的。