Печать шестнадцатеричных констант с плавающей точкой из массива байтов - PullRequest
2 голосов
/ 10 августа 2009

Как можно вывести шестнадцатеричную константу с плавающей запятой, как указано в C99, из массива байтов, представляющих машинное представление значения с плавающей запятой? например учитывая

union u_double
{
    double  dbl;
    char    data[sizeof(double)];
};

Пример шестнадцатеричной константы с плавающей запятой представляет собой строку вида

0x1.FFFFFEp127f 

Синтаксис спецификации для этой формы литерала можно найти на сайте IBM , а краткое описание синтаксиса здесь на сайте GCC .

Функция printf может использоваться для этого на платформах с доступом к функциям C99 в стандартной библиотеке, но я хотел бы иметь возможность выполнять печать в MSVC, которая не поддерживает C99, с использованием стандарта C89 или C + + 98.

Ответы [ 4 ]

4 голосов
/ 10 августа 2009

printf инструкция гласит:

а, А

(C99; не в SUSv2) Для преобразования двойной аргумент преобразуется в шестнадцатеричное представление (с использованием букв abcdef) в стиле [-] 0xh.hhhhp d; для преобразования A используется префикс 0X, буквы ABCDEF и разделитель экспоненты P. Перед десятичной точкой стоит одна шестнадцатеричная цифра, а количество цифр после нее равно точности. Точность по умолчанию достаточна для точного представления значения, если точное представление в базе 2 существует, а в противном случае оно достаточно велико, чтобы различать значения типа double. Цифра перед десятичной запятой не указана для ненормированных чисел и не равна нулю, но в остальном не указана для нормализованных чисел.

1 голос
/ 10 августа 2009

Вы можете использовать frexp (), который есть в math.h по крайней мере с C90, а затем выполнить преобразование самостоятельно. Примерно так (не проверено, не предназначено для обработки границ, таких как NaN, бесконечности, ограничений буфера и т. Д.)

void hexfloat(double d, char* ptr)
{
    double fract;
    int    exp = 0;

    if (d < 0) {
        *ptr++ = '-';
        d = -d;
    }
    fract = frexp(d, &exp);

    if (fract == 0.0) {
        strcpy(ptr, "0x0.0");
    } else {
        fract *= 2.0;
        --exp;
        *ptr++ = '0';
        *ptr++ = 'x';
        *ptr++ = '1';
        fract -= 1.0;
        fract *= 16.0;
        *ptr++ = '.';
        do {
            char const hexdigits[] = "0123456789ABCDEF";
            *ptr++ = hexdigits[(int)fract]; // truncate
            fract -= (int)fract;
            fract *= 16;
        } while (fract != 0.0);
        if (exp != 0) {
            sprintf(ptr, "p%d", exp);
        } else {
            *ptr++ = '\0';
        }
    }
}
0 голосов
/ 11 августа 2009

Это может быть ответ «вне коробки», но почему бы не преобразовать double в строку, используя sprintf, а затем проанализировать строку для мантиссы и экспоненты, преобразовать их в

например, что-то вроде:

char str[256];
long long a, b, c;
sprintf(str, "%e", dbl);
sscanf(str, "%d.%de%d", &a, &b, &c);
printf("0x%x.%xp%x", a, b, c);

Я уверен, что вам придется изменить форматы для sprintf и sscanf. И вы никогда не получите первую шестнадцатеричную цифру между А и F. Но в целом, я думаю, что эта идея должна работать. И это просто.

Лучшим способом было бы найти библиотеку с открытым исходным кодом, которая реализует этот формат для printf (например, newlib, uClibc?), И скопировать то, что они делают.

0 голосов
/ 10 августа 2009
#include <stdint.h>
#include <stdio.h>

int main(void)
{
    union { double d; uint64_t u; } value;
    value.d = -1.234e-5;

    // see http://en.wikipedia.org/wiki/Double_precision
    _Bool sign_bit = value.u >> 63;
    uint16_t exp_bits = (value.u >> 52) & 0x7FF;
    uint64_t frac_bits = value.u & 0xFFFFFFFFFFFFFull;

    if(exp_bits == 0)
    {
        if(frac_bits == 0)
            printf("%s0x0p+0\n", sign_bit ? "-" : "");
        else puts("subnormal, too lazy to parse");
    }
    else if(exp_bits == 0x7FF)
        puts("infinity or nan, too lazy to parse");
    else printf("%s0x1.%llxp%+i\n",
        sign_bit ? "-" : "",
        (unsigned long long)frac_bits,
        (int)exp_bits - 1023);

    // check against libc implementation
    printf("%a\n", value.d);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...