Проблемы чисел с плавающей точкой
Всем привет, работаю java разработчиком уже 10 лет, в этом посте хотел бы привести пример, почему нужно с опаской подходить к использованию чисел с плавающей точкой. Проблемы возникают из-за двух ограничений:
невозможности представить некоторые дробные числа в конечном виде в двоичной кодировке;
ограниченного объема памяти, выделенного для хранения значения.
В результате может страдать точность, причем в не самых очевидных случаях. Например, сравниваем между собой два маленьких различных числа. Они, очевидно, различны:
double little1 = 0.0000000000000000000000000000000000000001;
double little2 = 0.0000000000000000000000000000000000000002;
print(little1 == little2); //false
Далее попробуем сложить эти два числа с большим, и проверим, совпадают ли суммы:
double big = 10000000000000000000000000000000000000.0;
print(big + little1 == big + little2); //true
Оказывается что суммы равны, хотя интуиция подсказывает обратное. Проблема в том, что число которое имеет много символов до точки и после точки, не может быть достаточно точно представлено в памяти, и его конец обрезается. Из-за чего вычисления приводят к равенству.
Тем кто вынужден работать с нецелыми числами, рекомендую присмотреться к BigDecimal. Всем удачи!
Проблемы с числами с плавуещей точкой в том, что IEEE 754 стандарт, по которому они представляются в железе недостаточно точный для современных компьютеров, а не потому что их нельзя представить в двоичном числе. Есть другие стандарты, которые не страдают от таких вещей, но их проблемно внедрить потому что поголовно всё железо сейчас на IEEE 754 и если кто-то поменяет его, то начнутся проблемы с совместимостью.
Вот, если с английским нет проблем, можно посмотреть интересную лекцию. На русском не нашёл её.