Будут ли операции с плавающей запятой на JVM давать одинаковые результаты на всех платформах?
Я использую Java в приложении, работающем на нескольких машинах, и все машины должны получать одинаковые результаты для математических операций. Безопасно ли использовать примитивы Java с плавающей запятой? Или я должен просто использовать математическую библиотеку с фиксированной точкой?
3 ответа:
Не вообще, нет. Тем не менее, вы можете использовать
strictfp
выражения:в выражении FP-strict все промежуточные значения должны быть элементами набора значений float или набора значений double, что означает, что результаты всех выражений FP-strict должны быть предсказаны арифметикой IEEE 754 на операндах, представленных с использованием одиночных и двойных форматов.
в выражении, которое не является FP-строгим, некоторая свобода действий предоставляется для реализация для использования расширенного диапазона экспонент для представления промежуточных результатов; чистый эффект, грубо говоря, заключается в том, что расчет может дать "правильный ответ" в ситуациях, когда исключительное использование набора значений с плавающей запятой или двойного набора значений может привести к переполнению или недоливу.
кроме
strictfp
, там жеStrictMath
что требует предсказуемости результатов для трансцендентальных и других функций.
JVM должен последовательно реализовывать спецификацию IEEE, и эта спецификация является очень технической и точной. Примитивы с плавающей точкой float и double are то же самое на всех платформах.
разница заключается только в обработке промежуточных результатов и в том, что реализация виртуальной машины может использовать форматы float-extended-exponent и double-extended-exponent при оценке выражений с участием локальных объектов в одном кадре исполнение.
Так что если у вас есть код типа:
double d1 = 0.342; double d2 = 1.328479; double d3 = 4.99384728796; System.out.println(d1 * d2 / d3);
и это не в строгом контексте FP, возможно, что у вас будут различия между различными JVMs во время выполнения. Это связано с тем, что при оценке выражения d1*d2/d3 промежуточный результат d1*d2 используется в выражении "промежуточный результат"/d3, а JVM может использовать форматы с плавающей расширенной экспонентой и двойной расширенной экспонентой для хранения "промежуточного результата".
получить вокруг этого вы можете использовать strictfp или StrictMath, как ответили здесь Другие, или избегать использования промежуточных результатов в своих выражениях. Один из способов сделать это-сохранить любой промежуточный результат в куче. Например, следующим образом:
class MyClass { static double d1 = 0.342; static double d2 = 1.328479; static double d3 = 4.99384728796; static double intermediate_result = 0d; public static void main(String[] args) { intermediate_result = d1 * d2; System.out.println(intermediate_result / d3); } }