문제

계산을 해야 해요 Math.exp() Java에서 매우 자주 발생하는 경우 기본 버전을 보다 빠르게 실행하는 것이 가능합니까? 자바'에스 Math.exp()??

jni + C만 시도했지만 일반 것보다 느립니다. 자바.

도움이 되었습니까?

해결책

자신만의 exp() 구현을 작성하려면 +1하세요.즉, 이런 경우 정말 애플리케이션의 병목 현상.약간의 부정확성을 처리할 수 있다면 매우 효율적인 지수 추정 알고리즘이 많이 있으며 그 중 일부는 수세기 전으로 거슬러 올라갑니다.내가 이해하는 바에 따르면, "정확한" 결과를 반환해야 하는 알고리즘의 경우에도 Java의 exp() 구현은 상당히 느립니다.

아, 그리고 순수 Java로 exp() 구현을 작성하는 것을 두려워하지 마세요.JNI에는 많은 오버헤드가 있으며 JVM은 때때로 C/C++가 달성할 수 있는 것 이상으로 런타임에 바이트코드를 최적화할 수 있습니다.

다른 팁

이는 이미 여러 번 요청되었습니다(예: 여기).다음은 Math.exp()에 대한 근사치입니다. 이 블로그 포스팅:

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

이는 기본적으로 2048개의 항목과 항목 간의 선형 보간을 포함하는 조회 테이블과 동일하지만 이 모든 것은 IEEE 부동 소수점 트릭을 사용합니다.내 컴퓨터의 Math.exp()보다 5배 빠르지만 -server로 컴파일하면 크게 달라질 수 있습니다.

자바를 사용하세요.

또한 exp의 결과를 캐시한 다음 다시 계산하는 것보다 더 빠르게 답을 찾을 수 있습니다.

루프가 호출하는 것이 무엇이든 래핑하고 싶을 것입니다. Math.exp() C에서도 마찬가지다.그렇지 않으면 Java와 C 간의 마샬링 오버헤드가 성능 이점을 압도하게 됩니다.

일괄적으로 수행하면 더 빠르게 실행할 수 있습니다.JNI 호출을 수행하면 오버헤드가 추가되므로 계산해야 하는 각 exp()에 대해 JNI 호출을 수행하고 싶지 않습니다.100개의 값 배열을 전달하고 결과를 얻어 성능에 도움이 되는지 확인해 보겠습니다.

진짜 질문은 이것이 당신에게 병목 현상이 되었는가입니다.애플리케이션을 프로파일링한 후 이것이 속도 저하의 주요 원인임을 발견했습니까?

그렇지 않다면 Java 버전을 사용하는 것이 좋습니다.개발 속도가 느려질 수 있으므로 사전 최적화를 시도하지 마십시오.문제가 되지 않을 수도 있는 문제에 오랜 시간을 소비할 수도 있습니다.

즉, 귀하의 테스트가 귀하의 답변을 제공했다고 생각합니다.jni + C가 느린 경우 java 버전을 사용하세요.

커먼즈 수학3 최적화된 버전과 함께 제공됩니다: FastMath.exp(double x).내 코드 속도가 크게 향상되었습니다.

파비앙 몇 가지 테스트를 실행한 결과 속도가 거의 두 배나 빠르다는 것을 알았습니다. Math.exp():

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

다음은 javadoc입니다.

exp(x)를 계산합니다. 함수 결과는 거의 반올림됩니다.입력 값의 99.9%에 대해 이론적인 값으로 올바르게 반올림됩니다. 그렇지 않으면 1 UPL 오류가 발생합니다.

방법:

    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)

정확성:계산은 63비트 정밀도로 수행되므로 결과는 입력 값의 99.9%에 대해 올바르게 반올림되어야 하며 그렇지 않은 경우 ULP 오류는 1 미만이어야 합니다.

Java 코드는 JIT(Just-In-Time) 컴파일러를 사용하여 네이티브 코드로 컴파일되므로 실제로 JNI를 사용하여 네이티브 코드를 호출할 이유가 없습니다.

또한 입력 매개변수가 부동 소수점 실수인 메서드의 결과를 캐시해서는 안 됩니다.시간이 지남에 따라 얻은 이득은 사용된 공간의 양에 따라 매우 많이 손실됩니다.

JNI 사용 시의 문제점은 JNI 호출과 관련된 오버헤드입니다.요즘 Java 가상 머신은 상당히 최적화되어 있으며 내장 Math.exp()에 대한 호출은 C exp() 함수를 직접 호출하도록 자동으로 최적화되며 직접 x87 부동 소수점 어셈블리로 최적화될 수도 있습니다. 지침.

JNI 사용과 관련된 오버헤드가 있습니다. 다음도 참조하세요.http://java.sun.com/docs/books/performance/1st_edition/html/JPNativeCode.fm.html

따라서 다른 사람들이 제안한 대로 JNI 사용과 관련된 작업을 대조해 보십시오.

귀하의 필요에 맞게 직접 작성하십시오.

예를 들어, 모든 지수가 2의 거듭제곱인 경우 비트 이동을 사용할 수 있습니다.제한된 범위 또는 값 집합으로 작업하는 경우 조회 테이블을 사용할 수 있습니다.정확한 정밀도가 필요하지 않은 경우 부정확하지만 더 빠른 알고리즘을 사용합니다.

JNI 경계를 넘어 호출하는 것과 관련된 비용이 있습니다.

exp()를 호출하는 루프를 네이티브 코드로 이동하여 네이티브 호출이 하나만 있으면 더 나은 결과를 얻을 수 있지만 순수 Java 솔루션보다 훨씬 빠를지는 의문입니다.

귀하의 애플리케이션에 대한 세부 사항은 모르지만 호출에 대해 가능한 인수 세트가 상당히 제한되어 있는 경우 미리 계산된 조회 테이블을 사용하여 Java 코드를 더 빠르게 만들 수 있습니다.

달성하려는 작업에 따라 더 빠른 exp 알고리즘이 있습니다.문제 공간이 특정 범위로 제한되어 있습니까? 특정 해상도, 정밀도 또는 정확도 등만 필요한가요?

문제를 아주 잘 정의한다면, 예를 들어 거의 모든 다른 알고리즘을 물 밖으로 날려버릴 보간법이 포함된 테이블을 사용할 수 있다는 것을 알게 될 것입니다.

성능 균형을 얻기 위해 exp에 어떤 제약을 적용할 수 있나요?

-아담

피팅 알고리즘을 실행하고 피팅 결과의 최소 오차는 Math.exp ()의 정밀도보다 훨씬 큽니다.

초월 함수는 항상 덧셈이나 곱셈보다 훨씬 느리고 잘 알려진 병목 현상이 있습니다.값이 좁은 범위에 있다는 것을 알고 있다면 간단히 조회 테이블(두 개의 정렬된 배열;하나의 입력, 하나의 출력).Arrays.binarySearch를 사용하여 올바른 인덱스를 찾고 [index] 및 [index+1]의 요소로 값을 보간합니다.

또 다른 방법은 숫자를 나누는 것입니다.예를 들어 보겠습니다.3.81을 3+0.81로 나눕니다.이제 e = 2.718을 세 번 곱하면 20.08이 됩니다.

이제 0.81로.0과 1 사이의 모든 값은 잘 알려진 지수 계열로 빠르게 수렴됩니다.

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

정확성을 위해 필요한만큼의 용어를 사용하십시오.불행히도 x가 1에 접근하면 속도가 느려집니다.x^4로 이동하면 올바른 2.2448 대신 2.2445를 얻게 됩니다.

그런 다음 결과를 2.781^3 = 20.08로 2.781^0.81 = 2.2445로 곱하면 결과 45.07이 2 천의 한 부분의 오류가 있습니다 (올바른 : 정확합니다.45.15).

더 이상 관련이 없을 수도 있지만 OpenJDK의 최신 릴리스에서는 알 수 있습니다(참조 여기), Math.exp는 내장형으로 만들어져야 합니다(이것이 무엇인지 모르는 경우 확인하세요). 여기).

이는 Hotspot VM이 런타임 시 프로세서별 exp 구현으로 Math.exp에 대한 호출을 대체한다는 의미이므로 대부분의 아키텍처에서 탁월한 성능을 제공합니다.아키텍처에 최적화되어 있으므로 이러한 호출을 이길 수 없습니다...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top