Math.pow дает разные результаты в зависимости от версии java
Я запускаю следующий код на JDK версии 1.7.0_60:
System.out.println(Math.pow(1.5476348320352065, (0.3333333333333333)));
Результат: 1.1567055833133086
Я запускаю точно такой же код на JDK версии 1.7.0.
Результат: 1.1567055833133089
Я понимаю, что double не бесконечно точен, но было ли изменение в спецификации java, которое вызывает разницу?
PS: Поскольку мы используем устаревшую систему, Big Decimal не является вариантом.
Изменить: мне удалось отследить время изменения: оно было введено в версии JDK версии 1.7.0_40 (по сравнению с версией 1.7.0_25).
Ответы
Ответ 1
Чтобы обеспечить согласованные результаты между всеми версиями Java, решение заключалось в использовании StrictMath.pow()
вместо Math.pow()
.
Для получения справочной информации о том, что может вызвать разницу, обратитесь к этому ответу.
Ответ 2
но было ли изменение спецификации java, которое вызывает разницу?
Нет * В соответствии с Javadocs для Math.pow
разница в размере до одного ULP (единица на последнем месте). Если мы посмотрим на ваши два значения:
System.out.printf("%016x\n", Double.doubleToLongBits(1.1567055833133086));
System.out.printf("%016x\n", Double.doubleToLongBits(1.1567055833133089));
получаем:
3ff281ddb6b6e675
3ff281ddb6b6e676
которые действительно отличаются одним ULP.
То, что вы видите, вероятно, связано с небольшими различиями в последовательности инструкций с плавающей запятой, используемых JDK/JVM для реализации этих операций.
* По крайней мере, насколько я знаю!
Ответ 3
В спецификации не было изменений, но в оптимизаторе точек доступа были некоторые изменения, которые могут (!) быть связаны с этим.
Я выкопал эти части кода:
(это не совсем версии, в которых эти изменения были введены, я просто выбрал их из-за информации о версии, которую вы предоставили).
Изменения (и то, что делает код вообще) намного превосходят то, что я могу проанализировать в разумные сроки, но, возможно, кто-то найдет эту ссылку интересной или полезной.
Ответ 4
Если вы хотите использовать повторяющиеся значения с плавающей запятой между JVM, вы можете использовать ключевое слово strictfp, см. следующий вопрос Когда следует использовать строку" strictfp " ключевое слово в java?