При работе с вещественными типами в Java есть несколько граблей, часть из них, не самые страшные, уже были упомянуты в предыдущей статье.
Теперь рассмотрим несколько других, наиболее интересных :) Которые не часто освещаются в книга по программированию на Java и соответственно часто вызывают недоумения у начинающих программистов и не только на Java, поскольку это связано с представлением чисел с плавающей точкой в процессорах.
Чтобы сразу стало понятно о чём пойдет речь, разберем простой пример. Как вы уже должны знать, вещественные литералы в Java, по умолчанию имеют тип double. Теперь допустим у нас есть вот такая строка:
double
d = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1;То есть мы 10 раз складываем число 0.1. Можно предположить что в результате получится 1, но как бы не так. Мы получим число очень близкое к единице но не единицу, например это может быть число:
0.9999999999999999
Если же мы этот же эксперимент проделаем для типа float:
float
f = 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f;то там будет другой результат:
1.0000001
Это объясняется разностью в точности представления вещественных чисел в типах double и float в двоичном формате (вспоминаем, что компьютер работает только с нулями и единицами :) ).
Более подробно и популярно почему так происходит можно почитать тут и тут. Чистая теори о представлении вещественных чисел тут.
Из этого следует, что вещественные числа обычно не сравнивают оператором ==, а проверяют что модуль разности двух чисел меньше какого-то маленького числа (погрешности вычислений).
Еще одними грабельками при вычислениях с вещественными числами может быть ситуация когда возможно подобрать такое положительное число Х при котором будет верно сравнение a+x == x, то есть прибавление какого-то числа к переменной не меняет ее значения.
Чтобы стало все понятнее приведу пример:
Вывод программы:
Приведу еще один интересный пример слева и его вывод ниже:
Как видим, в первом случае dd и ff не равны друг другу. Такое происходит при сужающем преобразовании.
Затем мы сделали наоборот и теперь dd равно ff. Весело, не правда ли? :)
Именно из-за такого поведения double и float не используют в финансовых расчётах.
И еще парочка статей на эту тему: раз и два.
Ну и на последок, очень хорошая статья на эту тему. А BigInteger и BigDecimal, рассматриваемые в ней, мы изучим чуть позже.
Комментариев нет:
Отправить комментарий