2017-08-08 3 views
1

IEEE 754倍精度のC++で16進数からfloat64への変換をしようとしています。 これは私がビットで演奏した初めてのことです。多分私のコードは十分にクリーンではありません。 なぜ私の仮名が私に奇妙な結果を与えているのか分かりませんが、私は何か間違っていると思います。16進数から浮動小数点へIEEE 754倍精度C++

long int raw = 0x40000F0000000001; 
int sign = raw >> 63; 
long int mantissa = (raw & 0xFFFFFFFFFFFFF); 
mantissa +=1; 
double exp = ((raw >> 52) & 0x7FF) - 1023; 
double result = pow(-1., sign) * mantissa * pow(2.0, exp); 
cout << "MANTISSA: " << mantissa << " EXP: " << exp << endl; 
cout << "RESULT: " << result << endl; 

、出力は次のとおりです。

MANTISSA: 16492674416642 EXP: 1 
RESULT: 3.29853e+13 

誰もがそれを行う方法を知っていますか?

あなたは

答えて

2
long int raw = 0x40000F0000000001; 

これは、実装がlongは、その多くのビットを保持するのに十分な長さであるかどうかを指定します(通常、Windows上では、32ビット、64ビットのプログラムをコンパイルする場合は、Linux上でそれは、ありませんが、ありません符号ビットが設定されている場合。)

int sign = raw >> 63; 

この行は、実装定義された動作を有しています。 (もっともらしい結果は1と-1ですが、「42」を指定し、実装を停止するには何もありません。)あなたはこれがあなたの問題であるuint64_t

long int mantissa = (raw & 0xFFFFFFFFFFFFF); 
mantissa +=1; 

としてrawを定義するはるかに良いでしょう。欠落している「1」ビットは、すべてのビットのの先頭にあります。 *あなたはその後、2である仮数部を持つことになります

- あなたは(あなたがすべてのそれらのF sおよび0秒をカウントする必要はありませんそのように、一定のconst uint64_t MantissaOffset = 1uLL << 52;const uint64_t MantissaMask = MantissaOffset-1;を定義したり、より良い)の代わりに0x1000000000000を追加する必要があります* 52指数を計算するときに、あなたがそれを説明するために必要な(大きすぎる。

double exp = ((raw >> 52) & 0x7FF) - 1023; 
double result = pow(-1., sign) * mantissa * pow(2.0, exp); 

...そして、もちろん、これはデノーマル、NaNのとINFファイルを考慮していません。

cout << "MANTISSA: " << mantissa << " EXP: " << exp << endl; 
cout << "RESULT: " << result << endl; 
1

あなたの仮数部がほとんど OKであることをMEEようだありがとう。 0x40000F0000000001の場合、分数は0xF0000000001(少なくとも52ビット)であり、正確には16492674416641です。正直言って私はなぜそれに1を追加するのか分からない。

あなたがそのゲームで遊ぶ方法を知りたい場合は、this wikipediaのページをご覧ください。ノート、また

Given the hexadecimal representation 3FD5 5555 5555 5555(16), 
    Sign = 0 
    Exponent = 3FD(16) = 1021 
    Exponent Bias = 1023 (constant value; see above) 
    Fraction = 5 5555 5555 5555(16) 
    Value = 2^(Exponent - Exponent Bias) × 1.Fraction – Note that Fraction must not be converted to decimal here 
     = 2^-2 × (15 5555 5555 5555(16) × 2^-52) 
     = 2^-54 × 15 5555 5555 5555(16) 
     = 0.333333333333333314829616256247390992939472198486328125 
     ˜ 1/3 

:あなたは64ビット値を扱うようには章の終わりには、それから、二重を取得する方法の非常に良い例がステップによって、64ビットの生の表現のステップだあり64ビットのサイズを保証するuint64_tタイプを使用するのが安全です。 <stdint.h>ヘッダーを入力して使用できます。

+0

あなたの例のコードは '1.Fraction'を示しているので、彼は '1' を追加しています。そして、たくさんの5を抽出した後、それは '15 ... 'を使用します - それは彼が追加しようとしている先頭の1です。 –

+0

@MartinBonnerそれでは、あなたの答えですでにカバーしているように、確かに '+ = 1'ではありません。 –

関連する問題