Подтвердить что ты не робот

Каковы преимущества точности и производительности использования Math.fma?

Я заметил только существование Math.fma(a, b, c) в Java 9, которое вычисляет a*b + c
(для double и float значения).

Возвращает комбинированное добавление трех аргументов; то есть возвращает точный продукт первых двух аргументов, суммированных с третьим аргументом, а затем округленный один раз до ближайшего float. Округление выполняется с округлением до ближайшего режима округления. Напротив, если a * b + c оценивается как регулярное выражение с плавающей запятой, задействованы две ошибки округления, первая для операции умножения, вторая для операции сложения.

Итак, похоже, что улучшает точность, делая 1 округление вместо 2. Правильно ли это? Это обусловлено возможностями ЦП, или мы можем рассчитывать на это всегда?

Я предполагаю, что это может быть реализовано с использованием специальных инструкций CPU. Это так? И если да, можем ли мы ожидать преимуществ производительности? Мне интересно узнать о фактических преимуществах с текущими платформами/процессорами, а также о гипотетических будущих преимуществах.

Изменить (пытаясь сделать его немного менее широким): я не забочусь о очень подробных ответах: да/нет, чтобы несколько элементов, чтобы исправить/подтвердить мое понимание, плюс несколько указателей, было бы достаточно для меня, чтобы отметить ответ, как принято. Меня действительно интересуют как аспекты точности, так и производительности,  и я думаю, что они идут вместе...

4b9b3361

Ответ 1

Да, FMA повышает точность по той причине, о которой вы говорили.

JVM использует инструкции CPU FMA, если они доступны. Однако FMA недоступен повсюду. Например, процессоры Intel x86 до Haswell этого не имеют. Это означает, что большинство процессоров Intel в настоящее время не имеют FMA.

Если CPU FMA недоступен, Java использует медленное решение очень: оно выполняет FMA с использованием java.math.BigDecimal (то есть текущего решения - оно может измениться в будущем, но я уверен, что это будет всегда медленнее по сравнению с CPU FMA).

Ответ 2

Я нахожусь на mac с 5-м поколением i7. Когда я это сделаю:

sysctl -n machdep.cpu.brand_string

Я вижу, что мой процессор Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz и что cu поддерживает FMA, вы можете видеть, что:

sysctl -a | grep machdep.cpu | grep FMA

и в результате я получаю строку, в которой присутствует эта строка. Теперь посмотрим, использует ли JVM это.

Эти методы (один для double и один для float) аннотируются с помощью @HotSpotIntrinsicCandidate, что означает, что JIT может заменить их фактическими инструкциями процессора, если они доступны, но это будет означать, что метод должен быть достаточно горячим - называется несколько раз и что JVM-зависимая вещь.

Я пытаюсь имитировать это с помощью:

 public static void main(String[] args) {

    double result = 0;
    for (int i = 0; i < 50_000; ++i) {
        result = result + mine(i);
    }
    System.out.println(result);
}

private static float mine(int x) {
    return Math.fma(x, x, x);
}

И я запустил это с помощью:

 java -XX:+UnlockDiagnosticVMOptions  
      -XX:+PrintInlining 
      -XX:+PrintIntrinsics 
      -XX:CICompilerCount=2 
      -XX:+PrintCompilation  
      org.so/FMATest

Там будет куча строк, но один из них:

 @ 6   java.lang.Math::fma (12 bytes)   (intrinsic)

Это означает, что JVM действительно использовал встроенный метод для инструкций FMA.