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

Почему Math.sin() делегирует StrictMath.sin()?

Мне было интересно, почему Math.sin(double) делегировать на StrictMath.sin(double), когда я нашел проблему в Reddit thread. Вышеупомянутый фрагмент кода выглядит следующим образом (JDK 7u25):

Math.java:

public static double sin(double a) {
    return StrictMath.sin(a); // default impl. delegates to StrictMath
}

StrictMath.java:

public static native double sin(double a);

Вторая декларация native, которая для меня разумна. В документе Math говорится, что:

Генераторам кода рекомендуется использовать собственные библиотеки на основе платформы или инструкции микропроцессора, где доступно (...)

И вопрос: не является ли родной библиотекой, которая достаточно подходит для платформы StrictMath? Что еще может знать JIT о платформе, чем установленная JRE (пожалуйста, сосредоточьтесь только на этом случае)? В словах, почему не Math.sin() native уже?

4b9b3361

Ответ 1

Я попытаюсь завершить всю дискуссию в одном сообщении.

Как правило, Math делегирует StrictMath. Очевидно, что вызов может быть inlined, так что это не проблема производительности.

StrictMath - это окончательный класс с методами native, поддерживаемый родными библиотеками. Можно подумать, что родные средства оптимальны, но это не обязательно должно быть так. Просматривая StrictMath javadoc, вы можете прочитать следующее:

(...) определения некоторых числовых функций в этом пакете требуют, чтобы они дали те же результаты, что и некоторые опубликованные алгоритмы. Эти алгоритмы доступны из известной сетевой библиотеки netlib как пакет "Свободно распределяемая математическая библиотека", fdlibm. Эти алгоритмы, написанные на языке программирования C, затем понимаются как выполняемые со всеми операциями с плавающей запятой, следуя правилам арифметики с плавающей запятой Java.

Насколько я понимаю, этот документ заключается в том, что встроенная библиотека, реализующая StrictMath, реализована в терминах библиотеки fdlibm, которая является многоплатформенной и, как известно, дает предсказуемые результаты. Поскольку это многоплатформенная платформа, нельзя ожидать, что она будет оптимальной для каждой платформы, и Я считаю, что это место, где смарт-JIT может точно настроить фактическую производительность, например. путем статистического анализа входных диапазонов и соответственно корректировки алгоритмов/реализации.

Копаясь глубже в реализации, быстро получается, что резервная копия исходной библиотеки StrictMath на самом деле использует fdlibm:

StrictMath.c источник в OpenJDK 7 выглядит следующим образом:

   #include "fdlibm.h"
   ...
   JNIEXPORT jdouble JNICALL
   Java_java_lang_StrictMath_sin(JNIEnv *env, jclass unused, jdouble d)
   {
       return (jdouble) jsin((double)d);
   }

и функция синуса определена в fdlibm/src/s_sin.c, ссылаясь в нескольких местах на функцию __kernel_sin, которая поступает непосредственно из заголовка fdlibm.h.


<суб > Хотя я временно принимаю свой собственный ответ, я был бы рад принять более компетентного, когда он появится.Суб >

Ответ 2

Почему Math.sin() делегирует StrictMath.sin()?

Компилятор JIT должен иметь возможность встроить вызов StrictMath.sin(a). Поэтому немного смысла создать дополнительный метод native для случая Math.sin()... и добавить дополнительные компиляторы JIT для оптимизации последовательности вызовов и т.д.

В свете этого ваше возражение действительно сводится к проблеме "элегантности". Но "прагматичная" точка зрения более убедительна:

  • Меньшее количество нативных вызовов делает ядро ​​JVM и JIT более легким в обслуживании, менее хрупким и т.д.

  • Если он не сломан, не исправляйте его.

По крайней мере, это то, как я представляю, как команда Java увидит это.

Ответ 3

Вопрос предполагает, что JVM фактически выполняет код делегирования. На многих JVM это не будет. Вызовы в Math.sin() и т.д. Потенциально будут заменены JIT с некоторым внутренним функциональным кодом (если это подходит) прозрачно. Обычно это делается незаметным образом для конечного пользователя. Это общий трюк для реализаторов JVM, где могут возникнуть интересные специализации (даже если этот метод не помечен как родной).

Обратите внимание, однако, что большинство платформ не могут просто отказаться от инструкции одного процессора для sin из-за подходящих диапазонов ввода (например, см. Обсуждение Intel).

Ответ 4

Math API допускает нестрогую, но более эффективную реализацию его методов, но не требует этого, и по умолчанию Math просто использует StrictMath impl.