0

我想使用fdlibm的 sqrt 实现。
此实现定义(根据字节序)一些用于访问double 的低/高 32 位的宏)以下列方式(此处:仅 little-endian-version):

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

flibm 的自述文件是这样说的(有点缩短)

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)

两者似乎都错了。对于每个温度值,高似乎都是空的。

使用 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

我建议看一下反汇编,看看为什么现有的“指针抨击”方法不起作用。如果没有它,您可能会使用更传统的东西,例如二进制移位(如果您使用的是 64 位系统)。

于 2010-11-29T18:17:37.553 回答
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))

请注意,这也修复了字节序依赖性(假设浮点和整数字节序相同)和_宏名称上的非法 - 前缀。

更好的方法可能是根本不将其分成高/低部分,而是直接使用uint64_t表示REP(x)

从标准的角度来看,这种联合的使用有点可疑,但比指针强制转换要好。在某些方面,使用强制转换unsigned char *并逐字节访问数据会更好,但更糟糕的是,您必须考虑字节序,而且可能会慢很多..

于 2010-11-29T19:36:42.917 回答