Компьютеры начали правильно хранить 0.1? - PullRequest
0 голосов
/ 01 июля 2018

Изучая арифметику с плавающей запятой, я кое-что натолкнулся на цитату: «число с плавающей запятой / double не может точно хранить 0,1».

Существует вопрос о SO, указывающий на то же самое, и принятый ответ также очень убедителен. Однако я подумал о том, чтобы попробовать его на своем компьютере, поэтому я написал следующую программу, как показано ниже:

double a = 0.1;

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

Console.Read();

и консоль с печатью True. Шокирует, как я уже убедился в чем-то другом. Может кто-нибудь сказать мне, что происходит с арифметикой с плавающей запятой? Или я только что получил компьютер, который хранит числовые значения как основание 10?

1 Ответ

0 голосов
/ 01 июля 2018

Ваша программа только проверяет, приближает ли компилятор значение 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,1000000000000000055511151231257827021181583404541015625 - это значение double, наиболее близкое к 0,1.

Есть еще моменты, когда вы можете увидеть некоторые очень странные эффекты. Хотя double определено как 64-битное число IEEE-754, спецификация C # позволяет промежуточным представлениям использовать более высокую точность. Это означает, что иногда простой акт присвоения значения полю может изменить результаты - или даже привести значение, которое уже double к double.

В вопросе, на который вы ссылаетесь, мы на самом деле не знаем, как получить исходное значение. Вопрос гласит:

У меня есть двойная переменная с именем x. В коде 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);
    }
}

Значение x будет примерно равно 0,1, но это не то же самое приближение, что и "ближайшее double значение к 0,1". В этом случае оно оказывается немного меньше 0,1 - значение в точности равно 0,09999999999999997779553950749686919152736663818359375, что не равно 0,1000000000000000055511151231257827021181583404541015625 ... поэтому при сравнении выводится значение False.

...