두 배의 전력으로 효율적인 10

Oct 22 2020

10을 두 배의 거듭 제곱으로 많이 올려야합니다.

수학 라이브러리보다 더 효율적인 방법이 pow(10,double)있습니까? 중요한 경우 내 복식은 항상 -5와 -11 사이에서 음수입니다.

pow (double, double)은 pow (10, double)에 필요한 것보다 더 일반적인 알고리즘을 사용하므로 가장 빠른 방법이 아닐 수 있습니다. 아래 답변 중 일부를 감안할 때 잘못된 가정 일 수 있습니다.

그 이유는 대수 보간입니다. x 및 y 값 테이블이 있습니다. 내 개체에는 알려진 x 값 (거의 항상 두 배)이 있습니다.

double Dbeta(struct Data *diffusion, double per){
  double frac;
  while(per>diffusion->x[i]){
      i++;
  }
  frac = (per-diffusion->x[i-1])/(diffusion->x[i]-diffusion->x[i-1]);
  return pow(10,log10DB[i-1] + frac * (log10DB[i]-log10DB[i-1]));
}

이 함수는 여러 번 호출됩니다. 프로파일 링을 살펴 보라는 말을 들었으므로 이것이 제가 먼저 할 일입니다.

10을 밑으로하는 대신 자연 로그를 사용할 수 있다는 말을 들었습니다. (내 어리 석음은 때때로 나 자신을 놀라게합니다.)

모든 것을 자연 로그로 대체하면 모든 것이 조금 더 빠르게 실행됩니다. 프로파일 링 (오늘 배운 새로운 단어)을 통해 내 코드의 39 %가 exp 함수에 사용된다는 것을 알게 되었기 때문에 실제로이 부분이 내 코드에 병목 현상을 일으켰는지 궁금해하는 사람들에게는 그랬습니다.

답변

3 PascalGetreuer Oct 22 2020 at 14:58

예, pow 함수는 느립니다 (벤치 마크를 요청하는 경우 곱하기 비용의 약 50 배).

  • 일부 로그 / 지수 속임수에 의해 10 ^ x를 다음과 같이 표현할 수 있습니다.

    10^x = exp(log(10^x)) = exp(x * log(10)).
    

    따라서를 사용하여 10 ^ x를 구현할 수 있습니다 exp(x * M_LN10). 이는 pow보다 효율적이어야합니다.

  • 이중 정확도가 중요하지 않은 경우 함수의 부동 버전 expf(또는 powf)을 사용하십시오 . 이중 버전보다 더 효율적이어야합니다.

  • 대략적인 정확도가 정상이면 [-5, -11] 범위에 대해 테이블을 미리 계산하고 선형 보간으로 빠른 조회를 수행합니다.

일부 벤치 마크 (glibc 2.31 사용) :

Benchmark                Time
---------------------------------
pow(10, x)               15.54 ns
powf(10, x)               7.18 ns
expf(x * (float)M_LN10)   3.45 ns
5 TomKarzes Oct 22 2020 at 14:53

들어 pow(10.0, n)는 빠른 설정을해야 c = log(10.0)한 번 계산할 수있다, 그 후에 사용 exp(c*n)속도보다 훨씬해야하는 pow(10.0, n)(가 계산하는 것을 제외하고 기본적으로 내부적으로 같은 일을하고있는 log(10.0)반복하는 대신 한 번만). 그 외에는 할 수있는 일이 많지 않을 것입니다.