Когда я должен использовать ключевое слово strictfp в Java?

258

Я посмотрел, что это делает, но есть ли у кого-нибудь пример, когда вы будете использовать strictfpключевое слово в Java? Кто-нибудь на самом деле нашел применение для этого?

Будут ли какие-либо побочные эффекты от того, что я просто добавлю это на все мои операции с плавающей запятой?

GBA
источник
1
Всегда, если вам на самом деле не нужна производительность больше, чем вам нужна воспроизводимость.
Сурьма
1
@ Сурьма - или точность / правильность. Например, в x86 / x64 внутренне используются 80-битные регистры с плавающей запятой, поэтому результат будет более точным для длинных вычислений без строгого fp.
Роберт Фрейзер
1
@ Роберт На самом деле, спецификация гарантирует ограниченную точность мантиссы. Единственное отличие состоит в том, что он может использовать большую точность экспоненты, чем обычно, что имеет различия в редких случаях из-за двойного округления.
Сурьма
Я думаю, что в дополнение к возможности разбрасывать этот полезный модификатор по всему суставу, хорошей идеей могут быть новые примитивные типы данных sfloat & sdouble.
theRiley

Ответы:

274

Strictfp гарантирует, что вы получите точно такие же результаты от ваших вычислений с плавающей запятой на каждой платформе. Если вы не используете strictfp, реализация JVM может использовать дополнительную точность там, где это возможно.

Из JLS :

В выражении строгого FP все промежуточные значения должны быть элементами набора значений с плавающей запятой или набора двойных значений, подразумевая, что результаты всех выражений строгого FP должны быть теми, которые предсказаны арифметикой IEEE 754 для операндов, представленных с использованием одинарных и двойных форматов. , В выражении, не являющемся строгим с точки зрения FP, предоставляется некоторая свобода для реализации, чтобы использовать расширенный диапазон показателей для представления промежуточных результатов; общий эффект, грубо говоря, состоит в том, что вычисление может дать «правильный ответ» в ситуациях, когда исключительное использование набора значений с плавающей запятой или набора двойных значений может привести к переполнению или недостаточному заполнению.

Другими словами, речь идет о том, чтобы удостовериться в том, что Write-Once-Run-Anywhere действительно означает « Write-Once-Get-Equally-Wrong-Results-Everywhere» .

Благодаря строгому результату ваши результаты переносимы, без него они, скорее всего, будут точными.

Дэн Дайер
источник
28
Используйте его для воспроизводимых научных результатов и точных единичных тестов.
Александр Дубинский
1
«Если вы не используете strictfp, реализация JVM может использовать дополнительную точность там, где она доступна», - вы делаете это звучит как плохая вещь: P
AMDG
@LinkTheProgrammer это, конечно, может быть плохо
Тим
@TimCastelijns Полагаю, Happy Wheels - это ваша ссылка? Повторы записи нажатий клавиш; из-за различий в точности реализации FP-math повторы точны только на аналогичном оборудовании. Можете ли вы назвать более реалистичную проблему, вызванную математической изменчивостью с плавающей точкой? Я могу представить, возможно, симулятор частиц, но что еще?
AMDG
Таким образом, это означает, что мы всегда должны использовать строгий fp в производстве, где задействовано несколько платформ?
beatrice
65

Википедия на самом деле имеет хорошую статью по этой теме здесь , со ссылкой на спецификацию Java.

Чтение между строк означает, что если вы не укажете strictfp, то у JVM и JIT-компилятора есть лицензия для вычисления ваших вычислений с плавающей запятой, как они захотят. В интересах скорости они, скорее всего, делегируют вычисления вашему процессору. С участиемstrictfp , вычисления должны соответствовать арифметическим стандартам IEEE 754, что на практике, вероятно, означает, что JVM выполнит вычисления.

Так почему вы хотите использовать strictfp? Один сценарий, который я вижу, - это распределенное приложение (или многопользовательская игра), где все вычисления с плавающей точкой должны быть детерминированными, независимо от того, какое оборудование или процессор лежат в основе. Какой компромисс? Скорее всего, время выполнения.

MattK
источник
5
«Расширенный диапазон экспонент для представления промежуточных результатов» - это не «лицензия для вычисления ваших вычислений с плавающей запятой так, как они хотят», и на практике даже strictfpвычисления используют даже бесполезный 8087 FPU. Это только тот случай, когда требуется немного осторожности. См stackoverflow.com/questions/18496560/...
Pascal Cuoq
Я согласен с @PascalCuoq re: «Лицензия для вычисления ваших вычислений с плавающей точкой, как они хотят» . Во всяком случае, в данном случае, по-видимому, происходит обратное, поскольку strictfpобеспечивается соответствие стандарту IEEE 754 (так что вы получите одинаковый результат на всех платформах). Единственный недостаток, который я вижу, это то, что вы можете потерять преимущества наличия действительно хорошего FPU, доступного на вашем родном оборудовании.
typeracer
25

Все началось с истории,

Когда java разрабатывался Джеймсом Гослингом, Гербертом и остальной его командой. Они имели в виду эту сумасшедшую вещь под названием независимость от платформы . Они хотели сделать дуб (Ява)настолько лучше, что он будет работать точно так же на любой машине с другим набором команд, даже на разных операционных системах. Но возникла проблема с десятичными числами, также известными как языки с плавающей запятой и double в языках программирования. Некоторые машины были построены нацелены на эффективность, а остальные нацелены на точность. Таким образом, более поздние (более точные) машины имели размер с плавающей запятой равным 80 битам, тогда как прежние (более эффективные / более быстрые) машины имели 64-битные двойные числа. Но это противоречило основной идее построения языка, независимого от платформы. Кроме того, это может привести к потере точности / данных, когда код создается на некотором компьютере (с двойным размером 64 бита) и запускается на другом типе компьютера (с двойным размером 80 бит).

Увеличение размера можно допустить, но уменьшение не может быть. Таким образом, они столкнулись с понятием строгого, то есть строгого с плавающей точкой . Если вы используете это ключевое слово с классом / функцией, тогда его число с плавающей запятой и двойные числа будут иметь одинаковый размер на любой машине. т.е. 32/64-бит соответственно.

AbhimanyuAryan
источник
8
строгий fp был введен в Java 1.2. Это было намного позже, чем когда был разработан дуб.
Турбьёрн Равн Андерсен
«десятичные числа, также известные как числа с плавающей запятой» - десятичное число означает основание 10 и не имеет ничего общего с представлениями с плавающей запятой.
aioobe
21

Вот несколько ссылок:

  • Использование strictfp (JDC Tech Tip)
  • jGuru: Для чего нужен модификатор strictfp ? Когда я рассмотрю возможность его использования?

    По сути, все сводится к тому, заботитесь ли вы о том, что результаты выражений с плавающей точкой в ​​вашем коде быстрые или предсказуемые. Например, если вам нужны ответы, которые предлагает ваш код, в которых используются значения с плавающей запятой для согласованности на разных платформах, используйте strictfp.

  • strictfp - Глоссарий Java

    Аппаратные средства с плавающей запятой вычисляются с большей точностью и с большим диапазоном значений, чем требует спецификация Java. Было бы странно, если бы некоторые платформы давали больше точности, чем другие. Когда вы используете strictfpмодификатор для метода или класса, компилятор генерирует код, который строго придерживается спецификации Java для идентичных результатов на всех платформах. Без strictfpэтого он немного слабее, но не настолько слаб, чтобы использовать защитные биты в Pentium для обеспечения точности 80 бит.

  • И, наконец, актуальная спецификация языка Java, §15.4 Выражения строгого FP :

    В выражении строгого FP все промежуточные значения должны быть элементами набора значений с плавающей запятой или набора двойных значений, подразумевая, что результаты всех выражений строгого FP должны быть теми, которые предсказаны арифметикой IEEE 754 для операндов, представленных с использованием одинарных и двойных форматов. , В выражении, не являющемся строгим с точки зрения FP, предоставляется некоторая свобода для реализации, чтобы использовать расширенный диапазон показателей для представления промежуточных результатов; общий эффект, грубо говоря, состоит в том, что вычисление может дать «правильный ответ» в ситуациях, когда исключительное использование набора значений с плавающей запятой или набора двойных значений может привести к переполнению или потере.

Я лично никогда не использовал это, хотя.

Майкл Майерс
источник
12

Как уже упоминалось в других ответах, это приводит к тому, что промежуточные результаты с плавающей запятой соответствуют спецификации IEEE. В частности, процессоры x86 могут хранить промежуточные результаты с точностью, отличной от спецификации IEEE. Ситуация усложняется, когда JIT оптимизирует конкретное вычисление; порядок следования инструкций может быть разным каждый раз, что приводит к немного другому округлению

Накладные расходы, понесенные строгим fp, вероятно, будут сильно зависеть от процессора и JIT. Эта статья в Википедии о SSE2 похоже, дает представление о проблеме. Таким образом, если JIT может генерировать инструкции SSE для выполнения вычислений, кажется, что strictfp не будет иметь никаких накладных расходов.

В моем текущем проекте есть несколько мест, где я использую строгий fp. Есть точка, где потенциальные космические лучи должны быть удалены из значений пикселей. Если какой-то сторонний исследователь имеет такое же значение пикселей и космический луч перед ними, они должны получить то же результирующее значение, что и наше программное обеспечение.

Шон Макколифф
источник
8
  • strictfp - это модификатор, который ограничивает вычисления с плавающей запятой согласно IEEE 754.

  • Это можно использовать для всего класса, например, «public strictfp class StrictFpModifierExample {}» или для метода «public strictfp void example ()». Если он используется в классе, то все методы будут следовать IEEE 754, а в случае метода - конкретный метод следуйте IEEE 754.

  • Почему он используется ?? ::: Поскольку разные платформы имеют различное аппаратное обеспечение с плавающей запятой, которое вычисляет с большей точностью и большим диапазоном значений, чем требует спецификация Java, что может давать различный вывод на различных пластинчатых формах. Таким образом, он подтверждает один и тот же вывод независимо от различий plateforms

  • Stringfp также обеспечивает преимущество в скорости и точности операций с плавающей запятой повышенной точности.

  • С этим ключевым словом нет недостатка, который мы можем использовать, когда выполняем вычисления с плавающей запятой.

  • Последнее, что я хочу сказать - это IEEE754, короче говоря, IEEE 754 определяет стандартный метод как для вычислений с плавающей запятой, так и для хранения значений с плавающей запятой либо в одном (32-битный, используется в Java-плавающих), или в двойном (64-битный, используется в Java) doubles) точность. Он также определяет нормы для промежуточных вычислений и для форматов с расширенной точностью.

Рахул Саксена
источник
2

strictfpявляется ключевым словом и может использоваться как модификатор без доступа к классам или методам (но не переменным). Пометка класса как strictfpозначает, что любой код метода в классе будет соответствовать стандартным правилам IEEE 754 для чисел с плавающей запятой.

Без этого модификатора плавающие точки, используемые в методах, могут вести себя в зависимости от платформы. С его помощью вы можете предсказать, как ваши плавающие точки будут вести себя независимо от базовой платформы, на которой работает JVM. Недостатком является то, что если базовая платформа способна поддерживать большую точность, strictfpметод не сможет воспользоваться этим.

Если вы не объявляете класс как strictfp, вы все равно можете получить strictfpповедение для каждого метода, объявив метод как strictfp.

~ SCJP Sun® Сертифицированный программатор для Java ™ 6 - Кэти Сьерра и Берт Бейтс ~

Шанака Джаялат
источник
0

Пример ниже может помочь в понимании этого более ясно: В Java всякий раз, когда мы используем поиск точной информации для любой операции, например, если мы делаем double num1 = 10e + 102; двойное число2 = 8e + 10; результат = num1 + num2;

        The output will be so long and not precise, becasue it is precissed by the hardware e.g JVM and JIT has the license 
        as long as we dont have specify it Strictfp

Marking it Strictfp will make the result Uniform on every hardware and platform, because its precised value will be same
One scenario I can see is in a distributed application (or multiplayer game) where all floating-point calculations need to 
be deterministic no matter what the underlying hardware or CPU is.
Neeraj
источник
0

Ключевое слово 'strictfp' используется для явного соответствия точности вычислений с плавающей запятой (float или double) в Java стандарту IEEE 754. Если вы не используете ключевое слово strictfp, точность с плавающей запятой зависит от аппаратного обеспечения целевой платформы.

Если интерфейс или класс объявляются с использованием Strongfp, то все методы и вложенные типы в этом интерфейсе или классе неявно являются строгими.

Ссылка ссылка

Хари Кришна
источник