7

まず、これは精度などの問題ではありません。

私の質問は、コンパイラが数値の表現方法をどのように決定するかです。

Cを例にとってみましょう。私は書きます

double d = 4.5632;

バイナリ表現をどのように選択しますか? 正確に表現されていないことはわかっていますが、最も近い表現可能な数値をどのように選択するのでしょうか? コンパイル時に行われますか?CPUまたはOSによって行われますか?

「気にしないで」などの回答は役に立ちませんまた、「プラットフォームによって異なります」も役に立ちません。プラットフォームを選択して説明することもできます。

4

5 に答える 5

6

コンパイラは決定しません (通常)。CPUには(通常)浮動小数点ユニットがあり、浮動小数点値を特定の形式(通常はIEEE-754)で表す必要があります。もちろん、まったく異なるアーキテクチャをエミュレートすることは可能です。その場合、コンパイラ/エミュレータの作成者は、まったく異なる表現を自由に選択できます。しかし、これは典型的ではありません。

特定の字句表現4.5632が基になる表現に変換される方法については、C 標準で指定されています。したがって、C99 標準のセクション 6.4.4.2 から (最も関連性の高い部分を強調表示しました):

仮数部分は (10 進数または 16 進数) の有理数として解釈されます。指数部分の数字シーケンスは 10 進整数として解釈されます。10 進浮動小数点定数の場合、指数は仮数部がスケーリングされる 10 の累乗を示します。16 進浮動小数点定数の場合、指数は仮数部がスケーリングされる 2 の累乗を示します。10 進浮動小数点定数の場合、および FLT_RADIX が 2 の累乗でない場合の 16 進浮動定数の場合、結果は最も近い表現可能な値、または最も近い表現可能な値のすぐ隣にあるより大きなまたはより小さな表現可能な値のいずれかであり、実装定義で選択されます。マナー. FLT_RADIX が 2 のべき乗である場合の 16 進浮動小数点定数の場合、結果は正しく丸められます。

これはコンパイル時に行われます (ただし、標準では義務付けられていません)。

于 2012-04-28T14:30:10.350 に答える
0

あなたの特定の例では、はい、バイナリ表現はコンパイル時にエンコードされます。おそらくCライブラリ(atod、sscanf、etc)を呼び出し、そのライブラリが切り捨てや丸めで行うことは何でも起こります。また、コンパイラの「機能」または「ルール」は、同じことを行うときに発生する実行時ルールと必ずしも同じではありません。とにかく浮動小数点との同等性をチェックするべきではありませんが、コンパイル時の値を取得してからプログラムに文字列を供給し、そのランタイムを変換する場合 (コマンドラインで値 4.5632 を渡し、ライブラリ呼び出しの 1 つを使用するとします)必ずしも同じ浮動小数点値が得られるとは限りません。私は、コンパイラ (gcc など) がコンパイル時定数で本当に悪い仕事をするのを見てきました。

double d; int a;
a 45632;
d = a;
d/=10000;

また、最適化したとしても、より適切で正確な回答が得られる傾向があります。

int から double への変換でハードウェア + OS エラーが発生するリスクがあります。Hauser は、int から float および float から int の操作で発生する傾向がある FPU エラーについてコメントしました。コンパイル時に、コンパイラーが文字列を浮動小数点数に直接変換するのではなく、文字通り 2 つの int を浮動小数点数に変換すると仮定したとしても。

このすべてをデモンストレーションしてから数年が経ちましたが、コンパイラが改善されたのかもしれません (疑わしい)。ハードウェアが改善されたことを願っています (おそらく、以前は、バグを簡単に見つけられずに fpu を見つけることは非常にまれでした)。

于 2012-04-28T14:44:34.903 に答える
0

double d = 4.5632;はい、コンパイル時の定数であるため、その特定の変換はコンパイル時に行われます。コードにコンパイルされるのは、ターゲット アーキテクチャで使用される浮動小数点形式でのこの値の表現です。32 ビット IEEE-754 表現の場合、これは0x409205BC. これが 4.5632 にやや近い値であることを CPU がどのように「認識する」かは、浮動小数点の規格自体に依存します。繰り返しになりますが、32 ビット IEEE-754 の場合、符号用に 1 ビット、指数用に 8 ビット、仮数用に 23 ビットがあります。

丸めに関しては、適用できる方法がいくつかあります。IEEE-754 仕様では、最も近い値に丸める、ゼロに丸める、負の無限大に丸める、正の無限大に丸めるという 4 つの方法が言及されています。

于 2012-04-28T14:35:10.300 に答える
0

コンパイラは、プラットフォーム上で実行するプログラムを生成します。プラットフォームはコンパイラよりも前に存在していた可能性があり、その逆も同様です。すべてのバイナリ表現は、基本的にコンパイラの出力の仕様である ABI を構成します。最終的には、何らかの理由で物事が行われますが、何が起こるかを正確に伝える ABI があることを願っています。

実際には、ほぼすべてのプラットフォームが IEEE 754、別名 IEC 559 に従って浮動小数点演算を実装しています。このかなり古い国際標準は、浮動小数点数のビットの意味と、プログラムの 10 進数表現を浮動小数点数に丸める方法を定義しています。ポイント値。

FPU を搭載していないプラットフォームでも、IEEE 754 数値のビットフィールドはファイル内でバイナリ形式で表示される可能性が高いため、通常はソフトウェアでパックおよびアンパックします。

GPU など、相互運用性と数値精度の要件が限られているプラ​​ットフォームでは、IEEE 754 で要求される精度の基準が緩和される可能性がありますが、IEEE 754 で定義されている数値範囲は、さまざまなアプリケーションに最適です。

もちろん、究極の移植性が必要な場合は、何にも依存できません。ただし、10 進数から 2 進数の FP への変換 (FPU 自体が 10 進数ではない場合) がコンパイル時に実行されることは間違いありません。

于 2012-04-28T14:35:41.877 に答える
0

特定の例は、10 進リテラルであるため、コンパイラによって変換されます。詳細が必要なので、gcc を選びましょう。real.c (それが現在のバージョンかどうかはわかりませんが、Google で見つけた最初のコピーでした) の real_from_string() という関数で変換を行います。それは本質的に長い除算で変換を行います: あなたの場合、45632/10000.

(10 進数から浮動小数点への変換はかなり複雑です。詳しく知りたい場合は、私のブログを参照してください。)

于 2012-04-28T17:50:08.107 に答える