[C]Что-то не понятное с веществинными числами
int main() {
double a = 40000.7771 - 0.0001;
double b = 40000.7781 - 0.0001;
if(a != 40000.777)
printf("a != 40000.777\n");
if(b != 40000.778)
printf("b != 40000.778\n");
return 0;
}
Вроде все просто, но результат выполнения программы поверг меня в небольшой шок. ибо вывело:
b != 40000.778
дума лаги, проверяю чему реально равно b, и шок усиливаеться, b=40000.778
разьясните, как такое может быть?
Помоему еще тема должна быть на форуме, но это все что нашла )).
Приведу вас еще в более шоковое состояние: например число 2.3 вообще не существует для машины :)
В инженерной записи числа используется знак, мантисса и порядок. Причем мантисса - это нормализованное число. В десятичной нотации числа раскладываются по степеням 10. Например:
1*10^0 + 5*10^(-1) = 1.5
В машине же используется двоичная и число раскладывается по степеням 2. Например:
1*2^0 + 1*2^(-1) = 1.5
Также как в десятичной нотации нельзя представить например число 1/3 в виде конечного ряда, так и некоторые числа нельзя представить в двоичной. Например в вашем случае получается следующее:
40000.7781 = 40000.778100000003
40000.7781 - 0.0001 = 40000.778000000006
40000.778 = 40000.777999999998
отсюда 40000.778 != 40000.778 :)
Также как в десятичной нотации нельзя представить например число 1/3 в виде конечного ряда, так и некоторые числа нельзя представить в двоичной. Например в вашем случае получается с ледующее:
40000.7781 = 40000.778100000003
40000.7781 - 0.0001 = 40000.778000000006
40000.778 = 40000.777999999998
отсюда 40000.778 != 40000.778 :)
приблизительно то же я сказал вчера автору на IRC. но вопрос в другом:
a = 40000.7771 - 0.0001;
тоже не даст 40000.777
тем не менее в этом случае - сообщение не выводится ;)
a = 40000.7771 - 0.0001;
тоже не даст 40000.777
тем не менее в этом случае - сообщение не выводится ;)
Так и 40000.777 и (40000.7771 - 0.0001) дают одинаковый результат -
40000.777000000002, поэтому и не выводится
Дело в том, что при переводе десятичной дроби в двоичную систем могут возникнуть бесконечные дроби в двоичной системе счисления (не уверен, периодические или нет). А тут ещё и накладываются правила округления, и получается что мы складываем два неточных значения, а потом ещё и округляем.
Взято отсюда Собственно мне над этим и предложил подумать человек, прочитавший эту тему там. Я уже после опубликования здесь, нашел ту тему с обьяснением
Периодические.
Понятия "рациональное число" и "иррациональное число" не зависят от системы счисления. А рациональные числа всегда представимы в виде периодической дроби (и наоборот, если число представимо периодической дробью, оно рационально).
Для работы с рациональными числами есть библиотечка в boost'е:
http://boost.org/libs/rational/index.html
Можно использовать для точного сравнения таких чисел, как ваши 40000.7781 и т. п.
А поскольку компьютер конечен, все числа в нем всегда рациональны :) так что имеет смысл подумать над использованием ее для точного сравнения всех чисел.