1

今のところ、移植性の問題は無視して、long double データ型はすべてのアーキテクチャで一貫した 16 バイトの値であり、IEEE 754 の 4 倍精度の 2 進浮動小数点形式として常にメモリに格納されるという前提で操作する必要があります。これは、左端のビットが符号ビットであり、その後に 15 ビットの指数が続き、さらに 10 進数の有効桁数を表す 112 ビットのバイナリ データが続くことを意味します。もちろん、10 進数や BCD ではなく、すべて 2 進数です。

したがって、メモリ内の 3 の表現は次のようになります。

(dbx) x &ld3 / 1 E
0xffffffff7ffff400: 0x40008000 0x00000000 0x00000000 0x00000000

C の次の行により、デバッガーから取得します。

long double ld3 = 3.0;

ここでは、最初の 16 ビット、つまり左端の 16 ビットが次のようになっていることがわかります。

0x4000h = 0100 0000 0000 0000b 

ここで、符号ビットは 0 であり、IEEE754 規則によって正の値を示し、指数値 100 0000 0000 0000b の 15 ビットがあります。のドキュメントを読んでからもう一度読み直すのに少し時間がかかりました:

http://en.wikipedia.org/wiki/Quadruple_precision

その指数は、額面通りに取ると 2^14 で、16,384 です。ただし、(2^14) - 1 の「ゼロ オフセット」値があり、これは 16,383 なので、上記の指数は実際には 16,384 - 16,383 = 1 です。

実際の数値領域のデータ、次の 112 ビットは 0x8000 0000 ... 0000h ですが、1000 0000 ... 0000 のように見えますが、間違っているようです。3 のバイナリ値は、2 ビットの 1 の後に 0 のスタックが続く必要があります。それで気になります。

そこで、long double 変数を 16 進バイトのシーケンスとして出力するコード ビットを書きたいと思いました。ただし、変数のアドレスからのオフセットとして実際にそれらのバイトを取得するという問題に遭遇します。

私はこれを試します:

uint8_t j = 0;
j = ( (uint8_t *)(&ld3) + 2 );
fprintf ( stdout , "         &ld3 = %p\n", &ld3 );
fprintf ( stdout , "byte 2 of ld3 = 0x%02x\n", j );

私はこれを見る :

         &ld3 = ffffffff7ffff4b0
byte 2 of ld3 = 0xb2

それがどこから来ているのかはわかりませんが、変数 ld3 が占めるメモリ領域内からではありません。

そのため、long double の 16 バイトを通過し、各バイトの 16 進値を出力する for ループを望んでいましたが、ポインターやアドレスなどのキャストについて何かひどく間違っていると思います。

だから私は質問だと思います... long double 変数内の特定のバイトを取得するための魔法の foo は何ですか?


フォローアップ : 以下のアドバイスを参考にして、最後の 2 ビットにわずかなノイズまたはエラーが見られるこの作業ケースを示すことができます。

#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    long double two_ld = 2.0;
    long double e64_ld;
    uint8_t byt = 0, k;

    e64_ld = expl(logl(two_ld)*(long double)64.0);

    fprintf ( stdout , " sizeof (_ld) = %i\n", sizeof(e64_ld) );
    fprintf ( stdout , "   ( 2 ^ 64 ) = %36.32Le\n", e64_ld );

    fprintf ( stdout , "              = 0x" );
    for ( k = 0; k<16; k++ )
        fprintf ( stdout , "%02x ", * ( (uint8_t *)(&e64_ld) + k ) );
    fprintf ( stdout , "\n" );

    return ( EXIT_SUCCESS );

}

出力が示すところ、右端のビットには、実際には存在してはならない値があります。

 sizeof (_ld) = 16
   ( 2 ^ 64 ) = 1.84467440737095516160000000000000e+19
              = 0x40 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 02 

それでも、対数を使用して 2^64 を計算したことを考えると、悪くはありません。

4

2 に答える 2

0

あなたの仮定はかなり間違っています。一般的なコンピューターで、3 つの異なる long double 表現に遭遇しました。

long double = 64 ビット IEEE 形式 (ARM プロセッサ、PowerPC、特定のコンパイラを使用した x86)

long double = 80 ビットの IEEE 形式と 48 の未使用ビット (コンパイラが異なる x86)

long double = 2 つの 64 ビット IEEE 番号 (特定のコンパイラ オプションを使用した PowerPC)。ここで、long double は、(x + y) = x を丸めるプロパティを持つ double のペア (x, y) です。

于 2015-05-31T09:10:56.360 に答える