0

fdlibmのsqrt実装を使用したい。
この実装では、(エンディアンに応じて)次の方法で(ダブルの下位/上位32ビットにアクセスするための)いくつかのマクロを定義します(ここでは、リトルエンディアンバージョンのみ)。

#define __HI(x) *(1+(int*)&x)
#define __LO(x) *(int*)&x
#define __HIp(x) *(1+(int*)x)
#define __LOp(x) *(int*)x

flibmのreadmeは、次のように言っています(少し短縮されています)

Each double precision floating-point number must be in IEEE 754 
double format, and that each number can be retrieved as two 32-bit 
integers through the using of pointer bashing as in the example 
below:

Example: let y = 2.0
double fp number y:     2.0
IEEE double format: 0x4000000000000000

Referencing y as two integers:
*(int*)&y,*(1+(int*)&y) =   {0x40000000,0x0} (on sparc)
            {0x0,0x40000000} (on 386)

Note: Four macros are defined in fdlibm.h to handle this kind of
      retrieving:

__HI(x)     the high part of a double x 
        (sign,exponent,the first 21 significant bits)
__LO(x)     the least 32 significant bits of x
__HIp(x)    same as __HI except that the argument is a pointer
        to a double
__LOp(x)    same as __LO except that the argument is a pointer
        to a double

If the behavior of pointer bashing is undefined, one may hack on the 
macro in fdlibm.h.

この実装とこれらのマクロをcbmcモデルチェッカーで使用したいと思います。これはansi-cに準拠している必要があります
何が問題なのか正確にはわかりませんが、次の例は、これらのマクロが機能していないことを示しています(リトルエンディアンが選択され、32ビットのマシンワードが選択されました)。

temp=24376533834232348.000000l (0100001101010101101001101001010100000100000000101101110010000111)
high=0                         (00000000000000000000000000000000)
low=67296391                   (00000100000000101101110010000111)

どちらも間違っているようです。tempのすべての値に対してHighは空のようです。

ansi-cで両方の32ワードにアクセスするための新しいアイデアはありますか?

更新:すべての回答とコメントをありがとう。あなたの提案はすべて私のために働いた。今のところ、「R ..」バージョンを使用することにし、エンディアンに関して私のツールで最も堅牢であると思われるため、これをお気に入りの回答としてマークしました。

4

3 に答える 3

4

なぜ労働組合を使わないのですか?

union {
    double value;
    struct {
        int upper;
        int lower;
    } words;
} converter;

converter.value = 1.2345;
printf("%d",converter.words.upper);

(動作コードは実装に依存し、内部表現と特定のデータ サイズに依存することに注意してください)

その上、構造体にビットフィールドを含めると、個々の浮動小数点部分 (符号、指数、および仮数) に個別にアクセスできます。

union {
    double value;
    struct {
        int upper;
        int lower;
    } words;
    struct {
        long long mantissa : 52; // not 2C!
        int exponent : 11;       // not 2C!
        int sign : 1;
    };        
} converter;
于 2010-11-29T18:26:56.603 に答える
3

あなたがしているようなポインターのキャストは、C 言語のエイリアシング規則に違反します (特定の非常に制限された場合を除いて、異なる型のポインターは同じデータを指していないとコンパイラーによって想定される場合があります)。より良いアプローチは次のとおりです。

#define REP(x) ((union { double v; uint64_t r; }){ x }).r
#define HI(x) (uint32_t)(REP(x) >> 32)
#define LO(x) (uint32_t)(REP(x))

これにより、エンディアンの依存関係 (浮動小数点と整数のエンディアンが同じであると仮定) と_、マクロ名の不正な -prefix も修正されたことに注意してください。

さらに良い方法は、それを高い部分と低い部分にまったく分割せず、uint64_t表現をREP(x)直接使用することです。

標準の観点からすると、この共用体の使用は少し疑わしいですが、ポインタ キャストよりは優れています。キャストを使用してunsigned char *バイトごとにデータにアクセスすることは、いくつかの点で優れていますが、エンディアンの考慮事項について心配する必要があり、おそらくはるかに遅くなるという点で悪化します..

于 2010-11-29T19:36:42.917 に答える
3

逆アセンブリを見て、既存の「ポインターバッシング」方法が機能しない理由を正確に確認することをお勧めします。これがない場合は、バイナリ シフトなどのより伝統的なものを使用できます (64 ビット システムを使用している場合)。

于 2010-11-29T18:17:37.553 に答える