Ответ, приведенный ниже, является выдержкой из сообщения об ошибке Oracle 6430675 at. Посетите отчет для полного объяснения.
Методы {Math, StrictMath.round оперативно определены как
(long)Math.floor(a + 0.5d)
для двойных аргументов. Хотя это определение обычно работает как положено, оно дает удивительный результат 1, а не 0, для 0x1.fffffffffffffp-2 (0.49999999999999994).
Значение 0,49999999999999994 является наибольшим значением с плавающей запятой меньше 0,5. В качестве шестнадцатеричного литерала с плавающей точкой его значение равно 0x1.fffffffffffffp-2, что равно (2 - 2 ^ 52) * 2 ^ -2. == (0,5 - 2 ^ 54). Следовательно, точное значение суммы
(0.5 - 2^54) + 0.5
равно 1 - 2 ^ 54. Это на полпути между двумя соседними числами с плавающей запятой (1 - 2 ^ 53) и 1. В арифметическом округлении IEEE 754 до ближайшего четного режима округления, используемого Java, когда результаты с плавающей запятой неточны, чем ближе эти два представимые значения с плавающей точкой, которые заключают в скобки точный результат, должны быть возвращены; если оба значения в равной степени близки, возвращается то, которое его последний бит ноль. В этом случае правильное возвращаемое значение из сложения равно 1, а не наибольшему значению меньше 1.
Пока метод работает, как определено, поведение на этом входе очень удивительно; спецификация может быть изменена на что-то более похожее на «Округление до ближайшего длинного, округление связывания», что позволит изменить поведение на этом входе.