2015-03-23 2 views
5

Я пытаюсь сравнить производительность pow(x,2.0) и pow(x,2.0000001), и я, хотя то, что 2.0 будет намного быстрее, но они с одинаковой скоростью. Я даже удалил оптимизацию JIT, запустив jar с параметром -Xint.Java Math.pow (x, 2.0) vs Math.pow (x, 2.0000001) performance

Любая идея, почему это так, пожалуйста? Спасибо большое!

+1

Реализация может проводить условную ветвь для проверки на предмет специального случая или для реализации всех случаев с одним и тем же кодом. Все, что имеет значение, - результат. Во время исполнения гарантии нет. (Не то, если вы не будете осторожны, вы увидите их, даже если они там). –

+0

Почему вы ожидаете повышения производительности? Тип обоих параметров - «double». –

+0

Потому что это просто использование одной магической реализации, которая специализируется на всех двухместных; он не использует какую-либо специальную магию для целых степеней. Если вы просто используете умножение напрямую ('x * x'), вы получите лучшие результаты. –

ответ

10

Несмотря на несправедливые downvotes, вопрос имеет смысл, поскольку он показывает реальную ошибку JVM.

При запуске Oracle JDK производительность Math.pow(x, 2.0) сильно варьируется между версиями JVM.

  • Перед JDK 7u40 Math.pow используемой программной реализации, то есть он просто называется __ieee754_pow функции, которая эмулирует работу в программном обеспечении. Это было довольно медленно, но у него был особый случай для y == 2.
  • Поскольку JDK 7u40 Math.pow стал встроенным JVM, который был переведен в инструкции FPU JIT. Однако при этой оптимизации частный случай был потерян, что привело к регрессии производительности для y == 2, см. bug JDK-8029302.
  • Эта регрессия производительности была исправлена ​​в JDK 8u25 и предстоящих 7u80. Поскольку JDK 8u25 Math.pow работает достаточно быстро для всех значений, но очень быстро для y == 2. См. related question.

P.S. Ориентировочное время в секундах для вызовов 100M от Math.pow на моей машине с различными версиями JDK.

   Math.pow(x, 2.0) Math.pow(x, 2.0000001) 
JDK 7u25   3.0    30.4 
JDK 7u40   11.1    11.1 
JDK 8u40   0.1    11.1  
+1

Когда вы говорите «реализация Java», вы на самом деле имеете в виду собственный метод, правильно? –

+1

Цитата из связанной ошибки JDK: «Использование» -XX: + UnlockDiagnosticVMOptions -XX: + PrintIntrinsics »показывает, что внутренняя реализация используется в обоих случаях». Таким образом, фактическое изменение было только в самом внутреннем, а не в том, что была введена внутренняя. –

+2

@MarkoTopolnik Ну, это было довольно глупо. Я имею в виду, что он не проползал через все [вещи JNI] (http://stackoverflow.com/a/24747484/3448419) (в этом смысле он был «внутренним» *), но он все равно должен был сделать родной вызов функции эмуляции.В JDK7u40 он стал «реальным внутренним» *, то есть реализация была записана в сборке и была включена в вызывающий. Я уточнил ответ, чтобы быть более точным. Спасибо за обзор :) – apangin