Как получить верхнее / нижнее машинное слово double в соответствии с IEEE 754 (ansi-c)? - PullRequest
0 голосов
/ 29 ноября 2010

Я хочу использовать реализацию sqrt fdlibm .
Эта реализация определяет (в соответствии с порядком байтов) некоторые макросы для доступа к младшему / старшему 32-битному двойному ) следующим образом (здесь: только версия с прямым порядком байтов):

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

В файле readme из 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 .
Я не знаю точно, что не так, но следующий пример показывает, что эти макросы не работают (был выбран little-endian, было выбрано 32-битное машинное слово):

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

Кажется, что оба не правы. High кажется пустым для каждого значения temp.

Какие-нибудь новые идеи для доступа к обоим 32 словам с ansi-c?

ОБНОВЛЕНИЕ: Спасибо за все ваши ответы и комментарии. Все ваши предложения сработали для меня. На данный момент я решил использовать версию "R .." и отметил это как любимый ответ, потому что он кажется самым надежным в моем инструменте в отношении порядка байтов.

Ответы [ 3 ]

4 голосов
/ 29 ноября 2010

Почему бы не использовать объединение?

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;
3 голосов
/ 29 ноября 2010

Приведение указателей, как вы делаете, нарушает правила псевдонимов языка Си (компилятор может предполагать, что указатели разных типов не указывают на одни и те же данные, за исключением некоторых очень ограниченных случаев).Лучшим подходом может быть:

#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 * и доступ к побайтовым данным в некоторых случаях будет лучше, но хуже в том, что вам придется беспокоиться о порядке следования байтов и, возможно, намного медленнее ..

3 голосов
/ 29 ноября 2010

Я бы посоветовал взглянуть на разборку, чтобы понять, почему не работает существующий метод "разбивки указателей". При его отсутствии вы можете использовать что-то более традиционное, например двоичный сдвиг (если вы работаете в 64-битной системе).

...