문제

컴파일 타임에 pow(10,x)를 계산하는 것이 가능합니까?

부동 소수점을 지원하지 않고 정수 나누기가 느린 프로세서가 있습니다.나는 컴파일 타임에 가능한 한 많은 계산을 수행하려고 노력하고 있습니다.두 가지를 모두 통과하면 특정 기능 하나의 속도를 극적으로 높일 수 있습니다. x 그리고 C/pow(10,x) 인수로 사용됩니다(x와 C는 항상 상수 정수이지만 각 호출마다 다른 상수입니다).다음을 수행하는 매크로를 도입하여 이러한 함수 호출을 오류 발생 가능성을 줄일 수 있는지 궁금합니다. 1/pow(10,x) 프로그래머에게 계산을 강요하는 대신 자동으로?

전처리기 트릭이 있나요?컴파일러가 라이브러리 호출을 강제로 최적화할 수 있나요?

도움이 되었습니까?

해결책

C 언어의 일부인 부동 소수점 값에 과학적 표기법을 사용할 수 있습니다.그것은 다음과 같습니다:

e = 1.602E-19   // == 1.602 * pow(10, -19)

앞에 숫자는 E ( E 어쩌면 자본이든 소규모든 1.602e-19)는 분수 부분이며, 그 뒤의 (부호 있는) 숫자 시퀀스는 다음과 같습니다. E 지수 부분이다.기본적으로 숫자는 다음 유형입니다. double, 그러나 부동 소수점 접미사(f, F, l 또는 L) 필요한 경우 float 또는 long double.

나는 이 의미 체계를 매크로에 포함하는 것을 권장하지 않습니다:

  1. 변수, 부동 소수점 값 등에 대해서는 작동하지 않습니다.
  2. 과학적 표기법이 더 읽기 쉽습니다.

다른 팁

int (또는 길고) 오버플로하기 전에 가능한 값은 거의 없습니다. 명확성을 위해 테이블로 만드십시오!

편집 : 플로트를 사용하는 경우 (당신처럼 보인다면), Compile Time에서 Pow () 함수를 실제로 Make Process에서 실행하고 파일에 값을 출력하지 않고 Compile Time에서 Pow () 함수를 호출 할 수 없습니다 ( 그런 다음 컴파일 된 헤더 파일).

GCC는 충분히 높은 최적화 수준 에서이 작업을 수행합니다 (-O1은 나를 위해 수행). 예를 들어:

#include <math.h>

int test() {
        double x = pow(10, 4);
        return (int)x;
}

-o1 -m32에서 컴파일 : :

        .file   "test.c"
        .text
.globl test
        .type   test, @function
test:
        pushl   %ebp
        movl    %esp, %ebp
        movl    $10000, %eax
        popl    %ebp
        ret
        .size   test, .-test
        .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
        .section        .note.GNU-stack,"",@progbits

이것은 캐스트 없이도 작동합니다. 물론 Linux와 같이 부동 소재로드 지침을 얻을 수 있습니다. 아비 FPU 레지스터에서 부동 소수점 반환 값을 전달합니다.

Boost.proprocessor로 수행 할 수 있습니다.

http://www.boost.org/doc/libs/1_39_0/libs/preprocessor/doc/index.html

암호:

#include <boost/preprocessor/repeat.hpp>

#define _TIMES_10(z, n, data) * 10
#define POW_10(n) (1 BOOST_PP_REPEAT(n, _TIMES_10, _))

int test[4] = {POW_10(0), POW_10(1), POW_10(2), POW_10(3)};

실제로 C 전 처리기를 이용하여 계산할 수 있습니다. C pow(10, x) 진짜 C 그리고 통합 x. @Quinmars가 지적했듯이 C는 과학 구문을 사용하여 수치 상수를 표현할 수 있습니다.

#define myexp 1.602E-19   // == 1.602 * pow(10, -19)

상수에 사용됩니다. 이것을 염두에두고 약간의 영리함으로, 우리는 취약한 매크로를 만들 수 있습니다. C 그리고 x 지수 토큰으로 결합하십시오.

#define EXP2(a, b) a ## b
#define EXP(a, b) EXP2(a ## e,b)
#define CONSTPOW(C,x) EXP(C, x)

이것은 이제 일정한 수치 값으로 사용할 수 있습니다.

const int myint = CONSTPOW(3, 4); // == 30000
const double myfloat = CONSTPOW(M_PI, -2); // == 0.03141592653

실제로, 당신은 GCC보다 더 강력한 사전 프로세서 방식 인 M4를 가지고 있습니다. 이 두 가지의 주요 차이점은 GCC는 재귀는 아니지만 M4는입니다. 컴파일 타임에서 산술을하는 것과 같은 일을 가능하게합니다 (그리고 훨씬 더!). 아래 코드 샘플은 당신이하고 싶은 일입니다. 나는 1 파일 소스에서 그것을 부피가 크게 만들었다. 그러나 나는 보통 M4의 매크로 정의를 별도의 파일에 넣고 makefile 규칙을 조정합니다. 이런 식으로, 귀하의 코드는 추악한 침입 M4 정의에서 여기에서 수행 한 C 소스 코드로 보관됩니다.

$ cat foo.c
define(M4_POW_AUX, `ifelse($2, 1, $1, `eval($1 * M4_POW_AUX($1, decr($2)))')')dnl
define(M4_POW, `ifelse($2, 0, 1, `M4_POW_AUX($1, $2)')')dnl

#include <stdio.h>

int                     main(void)
{
  printf("2^0 = %d\n", M4_POW(2, 0));
  printf("2^1 = %d\n", M4_POW(2, 1));
  printf("2^4 = %d\n", M4_POW(2, 4));

  return 0;
}

이 코드 샘플을 컴파일하는 명령 줄은 GCC와 M4가 표준 입력에서 읽을 수있는 능력을 사용합니다.

$ cat foo.c | m4 - | gcc -x c -o m4_pow -
$ ./m4_pow
2^0 = 1
2^1 = 2
2^4 = 16

이 도움을 바랍니다!

최근 버전의 GCC (약 4.3)는 GMP 및 MPFR을 사용하여 일정한보다 복잡한 기능을 평가하여 일부 컴파일 시간 최적화를 수행하는 기능을 추가했습니다. 이 접근법은 코드가 간단하고 휴대하기 쉬워지고 컴파일러가 무거운 리프팅을하도록 신뢰합니다.

물론, 그것이 할 수있는 일에는 한계가 있습니다. Changelog의 설명에 대한 링크는 다음과 같습니다., 여기에는 이에 의해 지원되는 기능 목록이 포함됩니다. 'Pow'는 그들 중 하나입니다.

값을 사용해야하는 경우 시간을 컴파일하십시오, 사용 과학적 표기법 1e2처럼 pow(10, 2)

컴파일 시간에 값을 채우고 나중에 사용하려면 실행 시간 그런 다음 조회 테이블을 사용하기 만하면됩니다 10의 23 가지 힘 만 그것은 정확히 표현할 수 있습니다 이중 정밀도

double POW10[] = {1., 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10,
1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};

위의 조회 테이블에서 런타임에서 10의 더 큰 전력을 얻을 수있어 10을 계속해서 곱할 필요없이 결과를 빠르게 얻을 수 있지만 결과는 x>와 함께 10EX를 사용할 때와 같이 10의 전력에 가까운 값입니다. 22

double pow10(int x)
{
   if (x > 22)
      return POW10[22] * pow10(x - 22);
   else if (x >= 0)
      return POW10[x];
    else
        return 1/pow10(-x);
}

음의 지수가 필요하지 않은 경우 최종 분기를 제거 할 수 있습니다.

메모리가 제약 인 경우 조회 테이블 크기를 더 줄일 수도 있습니다. 예를 들어, 지수가 홀수 일 때 10의 전력 만 저장하고 10을 곱하면 테이블 크기는 이제 절반에 불과합니다.

불행히도, 사전 처리기를 사용하여 라이브러리 통화를 미리 계산할 수 없습니다. X가 적분하다면 자신의 기능을 작성할 수 있지만 부동 소수점 유형이라면이 작업을 수행하는 좋은 방법이 없습니다.

Bdonlan의 리플레이는 자리에 있지만 자신의 사용자 정의 전처리 업체에서 코드를 구문 분석하고 분석하려는 경우 컴파일 상자에서 선택한 거의 모든 최적화를 수행 할 수 있습니다. Compiler를 호출하여 컴파일러에 도달하기 전에 자신의 사용자 정의 단계를 호출하는 암시 적 규칙을 무시하는 것은 대부분의 UNIX 버전에서 사소한 작업입니다.

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