11

コンパイル時に pow(10,x) を計算することは可能ですか?

浮動小数点をサポートせず、整数除算が遅いプロセッサを使用しています。コンパイル時にできるだけ多くの計算を実行しようとしています。xと の両方を引数として渡すと、特定の関数を劇的に高速化できC/pow(10,x)ます (x と C は常に定数の整数ですが、呼び出しごとに異なる定数です)。1/pow(10,x)プログラマーに計算を強制するのではなく 、自動的に実行するマクロを導入することで、これらの関数呼び出しのエラーを少なくできるかどうか疑問に思っています。

プリプロセッサのトリックはありますか? コンパイラーがライブラリー呼び出しを強制的に最適化することはできますか?

4

10 に答える 10

21

int(またはlong)をオーバーフローする前に可能な値はほとんどありません。明確にするために、それをテーブルにしてください!

編集:floatを使用している場合(あなたがそうであるように見えます)、makeプロセスで実行され、値をファイルに出力するコードを実際に記述せずに、コンパイル時にpow()関数を呼び出すことはできません(ヘッダーファイルなど)がコンパイルされます。

于 2009-06-30T21:20:47.097 に答える
20

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 ABIはFPUレジスタで浮動小数点の戻り値を渡すため、ここで浮動小数点のロード命令を取得します。

于 2009-06-30T21:25:40.423 に答える
11

Boost.Preprocessor でそれを行うことができます:

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)};
于 2009-06-30T21:53:42.927 に答える
8

C 言語の一部である浮動小数点値の科学表記法を使用できます。次のようになります。

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

E(Eおそらく大文字または小文字) の前の数字1.602e-19は小数部分であり、後の (符号付き) 数字シーケンスEは指数部分です。デフォルトでは、数値は 型ですが、またはが必要な場合は、浮動小数点サフィックス ( 、、または)doubleを付けることができます。fFlLfloatlong double

このセマンティックをマクロにパックすることはお勧めしません。

  1. 変数、浮動小数点値などでは機能しません。
  2. 科学表記法はより読みやすくなっています。
于 2011-10-14T21:08:45.740 に答える
7

実際、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
于 2014-03-09T12:28:11.240 に答える
4

実際、GCC よりも強力なプリプロセッサである M4 があります。これら 2 つの主な違いは、M4 が再帰的であるのに対し、GCC は再帰的ではないことです。これにより、コンパイル時に算術演算を実行するなどのことが可能になります (さらに多くのことも!)。以下のコード サンプルは、あなたがやりたいことですよね。1 ファイルのソースでかさばりました。しかし、私は通常、M4 のマクロ定義を別のファイルに入れ、Makefile ルールを調整します。このようにして、あなたのコードは、私がここで行った C ソース コードへの醜い侵入 M4 定義から保護されます。

$ 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

この助けを願っています!

于 2012-06-06T12:49:56.400 に答える
4

コンパイル時に値を使用する必要があるだけの場合は、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 > 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 を乗算すると、テーブル サイズは半分になります。

于 2015-04-22T05:59:01.987 に答える
3

GCC の最近のバージョン ( 4.3 前後) では、GMP と MPFR を使用して、定数であるより複雑な関数を評価することでコンパイル時の最適化を行う機能が追加されました。このアプローチにより、コードはシンプルで移植性が高くなり、面倒な作業はコンパイラに任せることができます。

もちろん、できることには限界があります。これでサポートされている関数のリストが含まれている changelog の説明へのリンクを次に示します。'pow' はそれらの 1 つです。

于 2009-06-30T23:07:49.330 に答える
0

残念ながら、プリプロセッサを使用してライブラリ呼び出しを事前に計算することはできません。xが整数の場合、独自の関数を作成できますが、浮動小数点型の場合、これを行うための適切な方法がわかりません。

于 2009-06-30T21:24:39.567 に答える
0

bdonlan のリプレイは適切ですが、独自のカスタム プリプロセッサでコードを解析および分析する意思がある場合は、コンパイル ボックスで選択したほぼすべての最適化を実行できることに注意してください。Unix のほとんどのバージョンでは、コンパイラを呼び出す暗黙のルールをオーバーライドして、コンパイラに到達する前に独自のカスタム ステップを呼び出すのは簡単な作業です。

于 2009-07-01T00:27:35.987 に答える