Предположим следующий класс:
class Test {
public static void main(String[] args) {
double result = Math.log(9) / Math.log(3);
System.out.println(result);
}
};
На машине Linux x86_64 (Linux 6.8.10-300.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Fri May 17 21:20:54 UTC 2024 x86_64 GNU/Linux) я получаю следующий результат:
2.0
На Mac M3 вместо этого я получаю следующее:
2.0000000000000004
Каковы возможные объяснения такого поведения, кроме ошибки JDK?
Версия JDK, используемая на обеих машинах, — Temurin-21.0.3+9.




В классе Математика говорится следующее предостережение:
В отличие от некоторых числовых методов класса
StrictMath, все реализации эквивалентных функций классаMathне определены для возврата побитовых одинаковых результатов. Это ослабление позволяет реализовать более эффективные реализации, где не требуется строгая воспроизводимость.
Это означает, что реализация может варьироваться в небольших пределах. Так что это не ошибка.
Тогда вам стоит рассмотреть арифметику с плавающей запятой. Мы можем заниматься настоящей арифметикой,
log(9)/log(3) = log(3^2)/log(3) = 2 log(3)/log(3) = 2
Java не будет делать за вас эти сокращения, он будет вычислять log(9), который не имеет точного непрерывного двоичного представления. Затем log(3) и затем выполните деление. Итак, происходит несколько приближений.
Верно, StrictMath дает одинаковый результат на обеих платформах. (Результат М3.) Спасибо за ответ.
У меня сложилось впечатление, что начиная с JEP 306 (в Java 17) этой разницы больше не должно быть.
@JoachimSauer Меня это тоже немного смущает. StrictMath.log(3) возвращает результат, отличный от Math.log(3).
Кажется, что оба они используют режим расчета strictfp, но StrictMath определяет конкретный алгоритм, который должен использоваться, в то время как Math имеет некоторую свободу в использовании фактического алгоритма.
Конечно, самая крутая часть — это Math.log просто делегирование в StringMath.log. Вы ожидаете получить одинаковые результаты для обоих... Единственное, что я могу сказать, это то, что Math.log - это @IntrinsicCandidate
Эти числа отличаются на один бит в наименее значимом месте. Пришло время избавиться от старого доброго Математика с плавающей запятой не работает?