bestsource

수학은 어때요?.NET Framework에 구현된 Pow()?

bestsource 2023. 5. 29. 11:03
반응형

수학은 어때요?.NET Framework에 구현된 Pow()?

저는 계산을 위한b 효율적인 접근법을 찾고 있었습니다.a = 2그리고.b = 50시작하기 위해, 저는 의 구현을 살펴보기로 결정했습니다.Math.Pow()기능.하지만 .NET Reflector에서 찾은 것은 다음과 같습니다.

[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);

전화를 걸 때 내부 상황을 확인할 수 있는 리소스는 무엇입니까?Math.Pow()기능?

MethodImplOptions.InternalCall

즉, 이 방법은 C++로 작성된 CLR에서 실제로 구현됩니다.Just-in-Time 컴파일러는 내부적으로 구현된 메서드로 테이블을 참조하고 C++ 함수에 대한 호출을 직접 컴파일합니다.

코드를 보려면 CLR의 소스 코드가 필요합니다.SSCLI20 분포에서 이를 확인할 수 있습니다..NET 2.0 시간대에 작성되었으며 다음과 같은 낮은 수준의 구현을 찾았습니다.Math.Pow()CLR의 이후 버전에 대해서는 여전히 대체로 정확합니다.

조회 테이블은 clr/src/vm/ecall.cpp에 있습니다.Math.Pow()다음과 같이 표시됩니다.

FCFuncStart(gMathFuncs)
    FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin)
    FCIntrinsic("Cos", COMDouble::Cos, CORINFO_INTRINSIC_Cos)
    FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
    FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
    FCIntrinsicSig("Abs", &gsig_SM_Flt_RetFlt, COMDouble::AbsFlt, CORINFO_INTRINSIC_Abs)
    FCIntrinsicSig("Abs", &gsig_SM_Dbl_RetDbl, COMDouble::AbsDbl, CORINFO_INTRINSIC_Abs)
    FCFuncElement("Exp", COMDouble::Exp)
    FCFuncElement("Pow", COMDouble::Pow)
    // etc..
FCFuncEnd()

"로 합니다.COMDouble" 파일은 clr/src/classlibative/float/compfloat.cpp입니다.코드는 생략하겠습니다. 직접 확인해 보세요.을 CRT라고 .pow().

유일하게 흥미로운 구현 세부사항은 표의 FC Intrinsic 매크로입니다.이것은 지터가 기능을 내재적으로 구현할 수 있다는 암시입니다.즉, 함수 호출을 부동 소수점 기계 코드 명령으로 대체합니다.이 경우에는 그렇지 않습니다.Pow()FPU 명령이 없습니다.하지만 다른 간단한 수술들은 확실히 그렇습니다.주목할 점은 이것이 C#의 부동소수점 연산을 C++의 동일한 코드보다 상당히 빠르게 만들 수 있다는 것입니다. 그 이유를 위해답변을 확인하십시오.

참고로 Visual Studio vc/crt/src 디렉터리의 전체 버전이 있는 경우에도 CRT의 소스 코드를 사용할 수 있습니다.당신은 벽에 부딪힐 것입니다.pow()하지만 마이크로소프트는 인텔로부터 그 코드를 구입했습니다.Intel 엔지니어보다 더 나은 작업을 수행할 가능성은 거의 없습니다.비록 내가 그것을 시도했을 때 내 고등학교 책의 정체성은 두 배나 빨랐지만:

public static double FasterPow(double x, double y) {
    return Math.Exp(y * Math.Log(x));
}

그러나 3개의 부동 소수점 연산에서 오류가 누적되고 Pow()가 가지고 있는 이상한 도메인 문제를 처리하지 않기 때문에 진정한 대체는 아닙니다.0^0과 -Infinity가 어떤 멱급수로 상승한 것처럼.

한스 패상의 대답은 훌륭하지만, 저는 만약에b다음은 정수입니다.a^b이진 분해를 사용하여 매우 효율적으로 계산할 수 있습니다.다음은 헨리 워렌의 '해커즈 딜라이트'에서 수정된 버전입니다.

public static int iexp(int a, uint b) {
    int y = 1;

    while(true) {
        if ((b & 1) != 0) y = a*y;
        b = b >> 1;
        if (b == 0) return y;
        a *= a;
    }    
}

그는 이 연산이 모든 b < 15에 대해 최적(최소한의 산술 연산 또는 논리 연산을 수행함)임을 언급합니다.또한 계산할 최적의 요인 시퀀스를 찾는 일반적인 문제에 대한 알려진 해결책은 없습니다.a^b광범위한 검색 이외의 다른 검색을 위해.NP-Hard 문제입니다.기본적으로 이는 이진 분해가 얻는 것만큼 좋다는 것을 의미합니다.

무료로 사용할 수 있는 C 버전이 표시된다면, 그것은 당신이 기대하는 것처럼 보이지 않습니다..NET 버전을 찾는 것은 당신에게 큰 도움이 되지 않을 것입니다. 왜냐하면 당신이 해결하고 있는 문제(즉, 정수가 있는 문제)는 크기 순서가 더 단순하고 제곱 알고리즘에 의한 지수화로 C# 코드의 몇 줄로 해결할 수 있기 때문입니다.

답을 검토한 결과, 백그라운드 계산에 대해 많은 것을 알게 된 내용은 다음과 같습니다.광범위한 테스트 적용 사례가 있는 코딩 플랫폼에서 몇 가지 해결 방법을 시도해 본 결과 매우 효과적인 방법을 찾았습니다(솔루션 3).

public double MyPow(double x, int n) {
    double res = 1;
    /* Solution 1: iterative : TLE(Time Limit Exceeded)
    double res = 1;
    var len = n > 0 ? n : -n;
    for(var i = 0; i < len; ++i)
        res *= x;   
    
    return n > 0 ? res : 1 / res; 
    */
    
    /* Solution 2: recursive => stackoverflow exception
    if(x == 0) return n > 0 ? 0 : 1 / x;
    if(n == 1) return x;
    
    return n > 0 ? x * MyPow(x, n - 1) : (1/x) * MyPow(1/x, -n); 
    */
    
    //Solution 3:
    if (n == 0) return 1;
    
    var half = MyPow(x, n / 2);
    if (n % 2 == 0) 
        return half * half;
    else if (n > 0) 
        return half * half * x;
    else 
        return half * half / x;
    
    /* Solution 4: bitwise=> TLE(Time Limit Exceeded)
    var b = n > 0 ? n : -n;        
    while(true) {
        if ((b & 1) != 0) 
            res *= x;
        
        b = b >> 1;
        
        if (b == 0) break;
        
        x *= x;
    }   
    return n > 0 ? res : 1 / res; 
    */
}

리트코드에서 허용되는 답변:

public class Solution {
    public double MyPow(double x, int n) {
        if(n==0) return 1;
        
        long abs = Math.Abs((long)n);
        
        var result = pow(x, abs);
            
        return n > 0 ? result : 1/result;
    }
    
    double pow(double x, long n){
        if(n == 1) return x;
        
        var result = pow(x, n/2);
        result = result * result * (n%2 == 1? x : 1);
        return result;
    }
}

언급URL : https://stackoverflow.com/questions/8870442/how-is-math-pow-implemented-in-net-framework

반응형