얼마 전에 라이브러리 함수를 사용하지 않고 를 계산하려고 시도한 코드를 작성했습니다 . 어제, 나는 이전 코드를 검토하고 있었고 가능한 한 빨리 (올바르게) 만들려고했습니다. 지금까지 내 시도는 다음과 같습니다.
const double ee = exp(1);
double series_ln_taylor(double n){ /* n = e^a * b, where a is an non-negative integer */
double lgVal = 0, term, now;
int i, flag = 1;
if ( n <= 0 ) return 1e-300;
if ( n * ee < 1 )
n = 1.0 / n, flag = -1; /* for extremely small n, use e^-x = 1/n */
for ( term = 1; term < n ; term *= ee, lgVal++ );
n /= term;
/* log(1 - x) = -x - x**2/2 - x**3/3... */
n = 1 - n;
now = term = n;
for ( i = 1 ; ; ){
lgVal -= now;
term *= n;
now = term / ++i;
if ( now < 1e-17 ) break;
}
if ( flag == -1 ) lgVal = -lgVal;
return lgVal;
}
여기에 내가 찾으려고 노력하고 그래서 전자 A는 그냥 n은, 그리고 그때의 로그 값을 추가 N을 는 1보다 작습니다.이 시점에서걱정없이log(1-x)의 Taylor 확장을사용할 수 있습니다.
최근에 수치 분석에 관심을 가지게되었으므로 질문을하는데 도움이되지 않는 이유는이 코드 세그먼트를 실제로 얼마나 빨리 실행할 수 있을까요? 내가 좋아하는, 계속 분수를 사용하여, 예를 들어, 다른 방법으로 전환해야합니까 이 ?
C 표준 라이브러리가 제공 기능은 거의 5.1 배 빠른 구현이보다 길다.
업데이트 1 : Wikipedia에 언급 된 쌍곡선 arctan 시리즈를 사용하면 계산이 C 표준 라이브러리 로그 함수보다 거의 2.2 배 느립니다. 비록 성능을 광범위하게 확인하지는 않았지만 더 많은 수의 경우 현재 구현이 매우 느립니다. 관리 할 수 있다면 넓은 범위의 숫자에 대한 오류 바운드 및 평균 시간에 대한 구현을 모두 확인하고 싶습니다. 두 번째 노력은 다음과 같습니다.
double series_ln_arctanh(double n){ /* n = e^a * b, where a is an non-negative integer */
double lgVal = 0, term, now, sm;
int i, flag = 1;
if ( n <= 0 ) return 1e-300;
if ( n * ee < 1 ) n = 1.0 / n, flag = -1; /* for extremely small n, use e^-x = 1/n */
for ( term = 1; term < n ; term *= ee, lgVal++ );
n /= term;
/* log(x) = 2 arctanh((x-1)/(x+1)) */
n = (1 - n)/(n + 1);
now = term = n;
n *= n;
sm = 0;
for ( i = 3 ; ; i += 2 ){
sm += now;
term *= n;
now = term / i;
if ( now < 1e-17 ) break;
}
lgVal -= 2*sm;
if ( flag == -1 ) lgVal = -lgVal;
return lgVal;
}
어떤 제안이나 비판도 감사합니다.
double series_ln_better(double n){ /* n = e^a * b, where a is an non-negative integer */
double lgVal = 0, term, now, sm;
int i, flag = 1;
if ( n == 0 ) return -1./0.; /* -inf */
if ( n < 0 ) return 0./0.; /* NaN*/
if ( n < 1 ) n = 1.0 / n, flag = -1; /* for extremely small n, use e^-x = 1/n */
/* the cutoff iteration is 650, as over e**650, term multiplication would
overflow. For larger numbers, the loop dominates the arctanh approximation
loop (with having 13-15 iterations on average for tested numbers so far */
for ( term = 1; term < n && lgVal < 650 ; term *= ee, lgVal++ );
if ( lgVal == 650 ){
n /= term;
for ( term = 1 ; term < n ; term *= ee, lgVal++ );
}
n /= term;
/* log(x) = 2 arctanh((x-1)/(x+1)) */
n = (1 - n)/(n + 1);
now = term = n;
n *= n;
sm = 0;
/* limiting the iteration for worst case scenario, maximum 24 iteration */
for ( i = 3 ; i < 50 ; i += 2 ){
sm += now;
term *= n;
now = term / i;
if ( now < 1e-17 ) break;
}
lgVal -= 2*sm;
if ( flag == -1 ) lgVal = -lgVal;
return lgVal;
}