Pregunta

Necesito calcular Math.exp() a partir de java con mucha frecuencia, es posible obtener una versión nativa para correr más rápido que java's Math.exp()??

He intentado sólo jni + C, pero es más lento que simplemente java.

¿Fue útil?

Solución

+1 a la escritura de su propia exp() implementación.Es decir, si este es realmente un cuello de botella en la aplicación.Si usted puede manejar con un poco de imprecisión, hay un número muy eficiente exponente algoritmos de estimación por ahí, algunos de ellos datan de siglos atrás.Como yo lo entiendo, Java exp() la aplicación es bastante lento, incluso para los algoritmos que debe devolver "exacta" de los resultados.

Ah, y no tenga miedo de escribir que exp() implementación en puro Java.JNI tiene un montón de sobrecarga, y la JVM es capaz de optimizar el código de bytes en tiempo de ejecución, a veces, incluso más allá de lo que C/C++ es capaz de lograr.

Otros consejos

Esto ya ha sido solicitado en varias ocasiones (véase, por ejemplo, aquí).Aquí es una aproximación a las Matemáticas.exp(), copiado de esta publicación del blog:

public static double exp(double val) {
    final long tmp = (long) (1512775 * val + (1072693248 - 60801));
    return Double.longBitsToDouble(tmp << 32);
}

Es básicamente el mismo como una tabla de búsqueda con 2048 entradas y la interpolación lineal entre las entradas, pero todo esto con IEEE de punto flotante de trucos.Sus 5 veces más rápido que el de las Matemáticas.exp() en mi máquina, pero esto puede variar drásticamente si se compila con el servidor.

El uso de Java.

También, caché de resultados de la exp y, a continuación, usted puede buscar la respuesta más rápida de calcular de nuevo.

Te gustaría envolver el bucle de llamadas Math.exp() en C así.De lo contrario, la sobrecarga de cálculo de referencias entre Java y C van a abrumar a cualquier ventaja de rendimiento.

Usted puede ser capaz de conseguir que se ejecute más rápido si se hacen en lotes.Haciendo un JNI llamar aumenta la sobrecarga, por lo que no quiero hacer para cada exp() es necesario calcular.Me gustaría probar pasar un array de 100 valores y obtener los resultados para ver si le ayuda a rendimiento.

La pregunta real es, ha esto se convierta en un cuello de botella para usted?Han perfila su aplicación y ésta fue una de las principales causas de frenar?

Si no, me gustaría recomendar el uso de Java de la versión.Trate de no pre-optimizar como esto sólo le causa un desarrollo lento hacia abajo.Usted puede pasar una cantidad de tiempo en un problema que puede no ser un problema.

Dicho esto, creo que tu test te dio su respuesta.Si jni + C es más lento, el uso de java de la versión.

Commons Math3 los buques con una versión optimizada: FastMath.exp(double x).Lo hizo acelerar mi código significativamente.

Fabien hizo algunas pruebas y descubrió que era casi dos veces tan rápido como Math.exp():

 0.75s for Math.exp     sum=1.7182816693332244E7
 0.40s for FastMath.exp sum=1.7182816693332244E7

Aquí está el javadoc:

Calcula exp(x), el resultado de la función es casi redondo.Será correctamente redondeado al valor teórico para el 99,9% de los valores de entrada, de lo contrario no tendrá un 1 UPL error.

Método:

    Lookup intVal = exp(int(x))
    Lookup fracVal = exp(int(x-int(x) / 1024.0) * 1024.0 );
    Compute z as the exponential of the remaining bits by a polynomial minus one
    exp(x) = intVal * fracVal * (1 + z)

Precisión:El cálculo se realiza con 63 bits de precisión, por lo que debe ser el resultado correctamente redondeado para el 99,9% de los valores de entrada, con menos de 1 ULP de error en caso contrario.

Desde el código Java se pueda compilar a código nativo con el just-in-time (JIT) compilador, no hay realmente ninguna razón para utilizar JNI para llamar a código nativo.

También, usted no debe caché de los resultados de un método en el que los parámetros de entrada son de punto flotante los números reales.Los logros obtenidos en el tiempo va a estar muy perdido en la cantidad de espacio utilizado.

El problema con el uso de JNI es la sobrecarga que implica la realización de una llamada a la JNI.La máquina virtual de Java es bastante optimizado en estos días, y las llamadas a la incorporada en Matemáticas.exp() se optimizan automáticamente para llamar directamente a través de la C exp() función, y que incluso podría ser optimizado en recta x87 de punto flotante instrucciones de montaje.

No hay simplemente una sobrecarga asociada con el uso de la JNI, vea también:http://java.sun.com/docs/books/performance/1st_edition/html/JPNativeCode.fm.html

Así como otros han sugerido tratar de clasificar las operaciones que implican el uso de la JNI.

Escribir su propio, adaptado a sus necesidades.

Por ejemplo, si todos los exponentes son de la potencia de dos, se puede utilizar de desplazamiento de bits.Si usted trabaja con un rango limitado o de un conjunto de valores, puede utilizar tablas de búsqueda.Si usted no necesita el pin-punto de precisión, se utiliza una imprecisa, pero más rápido, algoritmo.

Hay un costo asociado con la llamada a través de la JNI de la frontera.

Si usted puede mover el bucle que se llama exp() en el código nativo, así que no es sólo una llamada nativa, entonces usted puede conseguir mejores resultados, pero dudo que va a ser significativamente más rápido que el de la pura solución de Java.

No sé los detalles de su aplicación, pero si usted tiene un bastante limitado conjunto de posibles argumentos para la llamada, se puede usar un pre-calculadas tabla de consulta para el código Java más rápido.

Hay más rápido de los algoritmos para la exp dependiendo de lo que tu estas tratando de lograr.Es el problema de espacio restringido a un cierto rango, no sólo se necesita una cierta resolución, precisión o exactitud, etc.

Si se define el problema muy bien, usted puede encontrar que usted puede utilizar una tabla con interpolación, por ejemplo, que sople el de casi cualquier otro algoritmo fuera del agua.

¿Qué restricciones pueden aplicar a exp para obtener el rendimiento de trade-off?

-Adam

Puedo ejecutar un algoritmo de ajuste y el mínimo de error de la instalación resultado es mucho más grande que la precisión de las Matemáticas.exp().

Funciones trascendentes son siempre mucho más lenta que la suma o la multiplicación y un conocido cuello de botella.Si usted sabe que sus valores están en un rango estrecho, usted puede simplemente hacer una búsqueda de mesa (Dos matriz ordenada ;una entrada, una salida).El Uso De Matrices.binarySearch para encontrar el índice correcto y interpolar el valor de los elementos en [índice] y [index+1].

Otro método es dividir el número.Tomemos, por ejemplo,3.81 y división que en 3+0.81.Ahora se multiplican e = 2.718 tres veces y obtener 20.08.

Ahora a 0,81.Todos los valores entre 0 y 1 convergen rápido con el conocido exponencial de la serie

1+x+x^2/2+x^3/6+x^4/24....etc.

Tomar tanto términos como usted necesidad de precisión;por desgracia, es más lento si x se aproxima a 1.Digamos que usted va a x^4, a continuación, obtener 2.2445 en lugar de la correcta 2.2448

Luego se multiplica el resultado 2.781^3 = 20.08 con 2.781^0.81 = 2.2445 y tienes el resultado 45.07 con un error de una parte de los dos mil (correcto:45.15).

Podría no ser relevante, pero solo para que lo sepas, en las nuevas versiones de la OpenJDK (ver aquí), Matemáticas.exp debería ser una intrínseca (si usted no sabe lo que es, comprobar aquí).

Esto hará que el rendimiento inmejorable en la mayoría de arquitecturas, porque significa que el Hotspot VM va a reemplazar a la llamada a las Matemáticas.exp por un procesador específico de la aplicación de exp en tiempo de ejecución.Usted nunca puede vencer a estas llamadas, ya que están optimizados para la arquitectura...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top