В Java представления и вычисления с плавающей точкой зависят от платформы. Модификатор strictfp гарантирует, что все операции с плавающей точкой на разных JVM и платформах будут обеспечивать согласованные и одинаковые результаты, предсказанные IEEE 754.
При использовании strictfp JVM выполняет вычисления с плавающей точкой, используя значения, которые могут быть представлены стандартными числами Java float или double, гарантируя, что результат вычислений будет точно совпадать на всех JVM и платформах.
Важный:
Начиная с Java 17( JEP 306 – Restore Always-Strict Floating-Point Semantics), Java предоставляет эту функциональность из коробки везде. Поэтому, начиная с JDK 17, все операции с плавающей точкой последовательно строгие.
1. Проблема с вычислениями с плавающей точкой
В Java вычисления с плавающей точкой непросты, и даже простые арифметические свойства не применимы к таким вычислениям. Например, сложения или умножения с плавающей точкой не ассоциативны. Другими словами,(x + y) + z не равно x +(y + z), где x, y и z — действительные числа.
Рассмотрим следующую программу Java, которая проверяет ассоциативность умножения. Результат — «ложь», что означает, что арифметика с плавающей точкой является методическим приближением вещественной арифметики.
double x = 5.899999;double y = 13.888345;double z = 14.463534545;double m1 =(x * y) * z; // 1185.1596894396725double m2 =(x *(y * z)); // 1185.1596894396728System.out.println(m1 == m2); //false
Основная причина этого приближения заключается в том, как вычисления с плавающей точкой дают разные результаты на разных платформах. Чтобы решить эту проблему, Java должна принять политику округления(по умолчанию это политика округления до ближайшего значения). Эта политика пытается округлить неточное значение до значения, ближайшего к бесконечно точному результату.
В Java эту проблему можно решить с помощью модификатора «strictfp», добавленного в Java 1.2.
Модификатор strictfp влияет только на операции с плавающей точкой. На целочисленные операции strictfp не влияет.
2. Где можно применить модификатор «strictfp»?
В Java модификатор strictfp можно использовать в:
- Класс – Весь код в этом классе и его вложенных классах будет использовать вычисления strictfp.
- Интерфейс – Все классы, которые реализуют этот интерфейс, будут использовать вычисления strictfp. Мы также можем использовать его в методах по умолчанию.
- Метод – Весь код внутри метода будет использовать вычисления strictfp.
strictfp class MyStrictClass {// class body}strictfp interface MyStrictInterface {// interface body}class MyClass {strictfp void myStrictMethod() {// method body}}
Кроме того, модификатор strictfp НЕЛЬЗЯ использовать в:
- Объявления переменных в классе
- Объявления конструктора в классе
- Статические или экземплярные блоки инициализации в классе
- «Абстрактные» классы и методы
- «Абстрактные» методы, объявленные в интерфейсе
strictfp double myVariable; // Error: strictfp not allowed hereclass MyClass {strictfp MyClass() { // Error: strictfp not allowed here// constructor body}}class MyClass {static {strictfp {// static initialization block body // Error: strictfp not allowed here}}}
Стоит отметить, что дочерний класс не наследует это поведение от родительского класса. Переопределяющий метод(в дочернем классе) может независимо выбрать strictfp, в то время как переопределяемый метод(в родительском классе) — нет, или наоборот.
3. Пример Java Strictfp
Давайте рассмотрим пример модификатора strictfp для сравнений с плавающей точкой, который даст абсолютно одинаковый результат на всех платформах и архитектурах процессоров.
В данном примере мы использовали значение Double.MAX_VALUE, которое является очень большим числом и имеет разные представления на каждой платформе. Используя strictfp, мы можем гарантировать, что данное вычисление всегда будет давать одно и то же значение.
public strictfp class Main{public static void main(String[] args){double MAX = Double.MAX_VALUE;System.out.println(Double.MAX_VALUE - 1);}}
Вывод программы.
1.7976931348623157E308
4. Влияние на производительность
Использование strictfp может оказать небольшое влияние на производительность, поскольку оно применяет более строгие правила для операций с плавающей точкой, что потенциально приводит к более затратным вычислениям.
Хотя влияние не такое уж и значительное.
Напишите мне ваши вопросы, связанные с ключевым словом strictfp в Java.