Как распечатать каждый бит числа с плавающей точкой?

Некоторые существующие ответы указывают, что это твердо. Это действительно верно, потому что Вам нужен полный компилятор для обнаружения случаев, в которых предописание было бы соответствующим. Вы наклоняете C++ синтаксического анализа, не зная то, что означают символы; грамматика просто слишком неоднозначна для этого. Необходимо знать, называет ли определенное имя класс (мог бы быть вперед - объявлен), или переменная (не может). Кроме того, необходимо быть осведомлены о пространстве имен.

5
задан Peter Mortensen 18 November 2017 в 12:12
поделиться

9 ответов

Приведите адрес вашего числа с плавающей запятой к адресу типа int того же размера и передайте это int в существующую функцию.

4
ответ дан 18 December 2019 в 07:30
поделиться

Благодарю Паскаля Куока за его комментарий. Наконец я понял, как решить свою проблему. Да, просто назначьте адрес числа с плавающей запятой указателю на целое число, а затем разыменуйте его. Вот мой код решения:

#include <stdio.h>

// bit returned at location
int bit_return(int a, int loc)   
{
    int buf = a & 1<<loc;

    if (buf == 0) return 0;
    else return 1; 
}

int main() 
{
    //11000010111011010100000000000000  
    // 1 sign bit | 8 exponent bit | 23 fraction bits
    float a = -118.625; 
    int *b;
    b = &a;

    int i;
    for (i = 31; i >= 0; i--)
    {
        printf("%d",bit_return(*b,i));
    }

    return 0;
}
5
ответ дан 18 December 2019 в 07:30
поделиться
static void printme(void *c, size_t n)
{
  unsigned char *t = c;
  if (c == NULL)
    return;
  while (n > 0) {
    --n;
    printf("%02x", t[n]);
  }
  printf("\n");
}

void fpp(float f, double d)
{
  printme(&f, sizeof f);
  printme(&d, sizeof d);
}
  • Примечание о параметрах float

    Убедитесь, что у вас есть прототип для fpp () в области видимости, когда вы вызываете его, иначе вы вызовете неясный K&R C против ANSI C проблема.

Обновление: двоичный вывод ...

  while (n > 0) {
    int q;
    --n;
    for(q = 0x80; q; q >>= 1)
      printf("%x", !!(t[n] & q));
  }
3
ответ дан 18 December 2019 в 07:30
поделиться

Хотя из комментариев кажется, что вывод битов внутреннего представления может быть тем, что нужно, вот код для выполнения того, о чем буквально спрашивал вопрос, без преобразования с потерями в int, которое некоторые предлагали:

Вывод числа с плавающей запятой в двоичном формате:

#include <stdio.h>
#include <stdlib.h>

void output_binary_fp_number(double arg)
{
    double pow2;

    if ( arg < 0 ) { putchar('-'); arg = -arg; }
    if ( arg - arg != 0 ) {
        printf("Inf");
    }
    else {
        /* compare and subtract descending powers of two, printing a binary digit for each */
        /* first figure out where to start */
        for ( pow2 = 1; pow2 * 2 <= arg; pow2 *= 2 ) ;
        while ( arg != 0 || pow2 >= 1 ) {
            if ( pow2 == .5 ) putchar('.');
            if ( arg < pow2 ) putchar('0');
            else {
                putchar('1');
                arg -= pow2;
            }
            pow2 *= .5;
        }
    }

    putchar('\n');

    return;
}

void usage(char *progname) {
    fprintf(stderr, "Usage: %s real-number\n", progname);
    exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
    double arg;
    char *endp;

    if ( argc != 2 ) usage(argv[0]);
    arg = strtod(argv[1], &endp);
    if ( endp == argv[1] || *endp ) usage(argv[0]);

    output_binary_fp_number(arg);

    return EXIT_SUCCESS;
}
2
ответ дан 18 December 2019 в 07:30
поделиться

Если вы хотите использовать функцию bit_return для числа с плавающей запятой, вы можете просто обмануть:

float f = 42.69;

for .... 
   bit_return((int) f, loc)

Приведение (int) заставит компилятор поверить, что вы работаете с целым числом, поэтому bit_return будет работать.

По сути, это то, что предлагал Паскаль.

РЕДАКТИРОВАТЬ:

Я стою исправлен Паскалем. Я думаю, что это будет соответствовать его последнему комментарию:

bit_return (*((float *) &f), loc)

надеюсь, что тогда я понял.

Другой альтернативой (с меньшим количеством скобок) было бы использование объединения для обмана типа данных.

1
ответ дан 18 December 2019 в 07:30
поделиться

В следующем коде предполагается, что числа с плавающей запятой и указатели имеют одинаковый размер, что верно для многих систем:

float myfloat = 254940.4394f;
printf("0x%p", *(void**)(&myfloat));
2
ответ дан 18 December 2019 в 07:30
поделиться

В языке C термин «бит» относится к элементу двоичного позиционного представления числа. Целые числа в C используют двоичное позиционное представление, поэтому они имеют «биты». Это биты, которые вы «видите» с помощью побитовых операторов (логических и сдвигов). Числа с плавающей запятой не используют это представление. Кроме того, представление чисел с плавающей запятой не определено спецификацией языка. Другими словами, числа с плавающей запятой в C не имеют «битов» , поэтому вы не сможете получить доступ любой из их «битов» любыми законными средствами языка, и именно поэтому вы не можете применять какие-либо побитовые операторы к объектам с плавающей запятой.

Сказав это, я ' Я подозреваю, что вас могут заинтересовать физические биты, представляющие объект с плавающей запятой. Вы можете заново интерпретировать память, занимаемую объектом с плавающей запятой (или любым другим объектом), как массив элементов unsigned char и вывести биты каждого из объектов unsigned char . Это даст вам карту всех физических битов, представляющих объект.

Однако это не будет в точности эквивалентно тому, что у вас есть в приведенном выше коде. Ваш код выше печатает биты представления значения целостного объекта (то есть это логические биты, которые я описал выше), в то время как подход переинтерпретации памяти даст вам биты объекта представление (т.е. физических битов). Но опять же, числа с плавающей запятой в C не Они имеют логические биты по определению.

Добавлено позже: Я считаю, что понимание разницы между концепциями физических и логических битов может быть нелегкой задачей для некоторых читателей. В качестве еще одного примера, который может помочь в понимании, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.

Я считаю, что понимание разницы между понятиями физических и логических битов может быть нелегкой задачей для некоторых читателей. В качестве еще одного примера, который может способствовать пониманию, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть на оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.

Я считаю, что понимание разницы между понятиями физических и логических битов может оказаться непростой задачей для некоторых читателей. В качестве еще одного примера, который может помочь в понимании, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.

В качестве еще одного примера, который может способствовать пониманию, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть на оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.

В качестве еще одного примера, который может способствовать пониманию, я хотел бы отметить, что нет абсолютно ничего, что могло бы помешать полностью совместимой реализации C на троичном оборудовании, то есть на оборудовании, которое вообще не имеет физических двоичных битов. . В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.

В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.

В такой реализации побитовые операции по-прежнему будут работать отлично, они все равно будут обращаться к двоичным битам, то есть к элементам [теперь только мнимого] двоичного позиционного представления каждого целого числа. Это будут логические биты, о которых я говорю выше.

3
ответ дан 18 December 2019 в 07:30
поделиться

У меня есть включенный код, который производит шестнадцатеричный вывод, который, я думаю, может помочь вам понять числа с плавающей запятой. Вот пример:

double: 00 00 A4 0F 0D 4B 72 42 (1257096936000.000000) (+ 0x1.24B0D0FA40000 x 2 ^ 40)

Из моего примера кода ниже вам должно стать очевидно, как выводить биты. Преобразуйте адрес двойной точности в unsigned char * и выведите биты sizeof (double) chars.

Так как я хочу вывести экспоненту и значащую (и знаковый бит) число с плавающей запятой, мой примерный код копается в битах стандартного представления IEEE-754 для 64-битных точка с плавающей точкой двойной точности в системе счисления 2. Поэтому я не использую sizeof (double) , кроме как для проверки того, что компилятор и я согласны с тем, что double означает 64-битное число с плавающей запятой.

Если вы хотите вывести биты для числа с плавающей запятой любого типа, используйте sizeof (double) вместо 8 .

void hexdump_ieee754_double_x86(double dbl)
{
    LONGLONG ll = 0;
    char * pch = (char *)&ll;
    int i;
    int exponent = 0;

    assert(8 == sizeof(dbl));

    // Extract the 11-bit exponent, and apply the 'bias' of 0x3FF.
    exponent = (((((char *)&(dbl))[7] & 0x7F) &lt;&lt; 4) + ((((char *)&(dbl))[6] & 0xF0) &gt;&gt; 4) & 0x7FF) - 0x3FF;

    // Copy the 52-bit significand to an integer we will later display
    for (i = 0; i &lt; 6; i ++)
        *pch++ = ((char *)&(dbl))[i];
    *pch++ = ((char *)&(dbl))[6] & 0xF;

    printf("double: %02X %02X %02X %02X %02X %02X %02X %02X (%f)",     
           ((unsigned char *)&(dbl))[0],
           ((unsigned char *)&(dbl))[1],
           ((unsigned char *)&(dbl))[2],
           ((unsigned char *)&(dbl))[3],
           ((unsigned char *)&(dbl))[4],
           ((unsigned char *)&(dbl))[5],
           ((unsigned char *)&(dbl))[6],
           ((unsigned char *)&(dbl))[7],
           dbl);

    printf( "\t(%c0x1.%05X%08X x 2^%d)\n", 
            (((char *)&(dbl))[6] & 0x80) ? '-' : '+',
            (DWORD)((ll & 0xFFFFFFFF00000000LL) &gt;&gt; 32),
            (DWORD)(ll & 0xFFFFFFFFLL),
            exponent);
}

Nota Bene: The Значение отображается в виде шестнадцатеричной дроби («0x1.24B0D0FA40000»), а показатель степени отображается в виде десятичной дроби («40»). Для меня это был интуитивно понятный способ отображения битов с плавающей запятой.


Если вы хотите вывести биты для числа с плавающей запятой любого типа, используйте sizeof (double) вместо 8 .

void hexdump_ieee754_double_x86(double dbl)
{
    LONGLONG ll = 0;
    char * pch = (char *)&ll;
    int i;
    int exponent = 0;

    assert(8 == sizeof(dbl));

    // Extract the 11-bit exponent, and apply the 'bias' of 0x3FF.
    exponent = (((((char *)&(dbl))[7] & 0x7F) &lt;&lt; 4) + ((((char *)&(dbl))[6] & 0xF0) &gt;&gt; 4) & 0x7FF) - 0x3FF;

    // Copy the 52-bit significand to an integer we will later display
    for (i = 0; i &lt; 6; i ++)
        *pch++ = ((char *)&(dbl))[i];
    *pch++ = ((char *)&(dbl))[6] & 0xF;

    printf("double: %02X %02X %02X %02X %02X %02X %02X %02X (%f)",     
           ((unsigned char *)&(dbl))[0],
           ((unsigned char *)&(dbl))[1],
           ((unsigned char *)&(dbl))[2],
           ((unsigned char *)&(dbl))[3],
           ((unsigned char *)&(dbl))[4],
           ((unsigned char *)&(dbl))[5],
           ((unsigned char *)&(dbl))[6],
           ((unsigned char *)&(dbl))[7],
           dbl);

    printf( "\t(%c0x1.%05X%08X x 2^%d)\n", 
            (((char *)&(dbl))[6] & 0x80) ? '-' : '+',
            (DWORD)((ll & 0xFFFFFFFF00000000LL) &gt;&gt; 32),
            (DWORD)(ll & 0xFFFFFFFFLL),
            exponent);
}

Nota Bene: Значение отображается в виде шестнадцатеричной дроби («0x1.24B0D0FA40000»), а показатель степени отображается в виде десятичной дроби («40»). Для меня это был интуитивно понятный способ отображения битов с плавающей запятой.


Если вы хотите вывести биты для числа с плавающей запятой любого типа, используйте sizeof (double) вместо 8 .

void hexdump_ieee754_double_x86(double dbl)
{
    LONGLONG ll = 0;
    char * pch = (char *)&ll;
    int i;
    int exponent = 0;

    assert(8 == sizeof(dbl));

    // Extract the 11-bit exponent, and apply the 'bias' of 0x3FF.
    exponent = (((((char *)&(dbl))[7] & 0x7F) &lt;&lt; 4) + ((((char *)&(dbl))[6] & 0xF0) &gt;&gt; 4) & 0x7FF) - 0x3FF;

    // Copy the 52-bit significand to an integer we will later display
    for (i = 0; i &lt; 6; i ++)
        *pch++ = ((char *)&(dbl))[i];
    *pch++ = ((char *)&(dbl))[6] & 0xF;

    printf("double: %02X %02X %02X %02X %02X %02X %02X %02X (%f)",     
           ((unsigned char *)&(dbl))[0],
           ((unsigned char *)&(dbl))[1],
           ((unsigned char *)&(dbl))[2],
           ((unsigned char *)&(dbl))[3],
           ((unsigned char *)&(dbl))[4],
           ((unsigned char *)&(dbl))[5],
           ((unsigned char *)&(dbl))[6],
           ((unsigned char *)&(dbl))[7],
           dbl);

    printf( "\t(%c0x1.%05X%08X x 2^%d)\n", 
            (((char *)&(dbl))[6] & 0x80) ? '-' : '+',
            (DWORD)((ll & 0xFFFFFFFF00000000LL) &gt;&gt; 32),
            (DWORD)(ll & 0xFFFFFFFFLL),
            exponent);
}

Nota Bene: The Значение отображается как шестнадцатеричная дробь («0x1.24B0D0FA40000»), а показатель степени отображается как десятичный («40»). Для меня это был интуитивно понятный способ отображения битов с плавающей запятой.

1
ответ дан 18 December 2019 в 07:30
поделиться

Выведите целую часть, затем '.', затем дробную часть.

float f = ...
int int_part = floor(f)
int fraction_part = floor((f - int_part) * pow(2.0, 32))

Затем вы можете используйте свой bit_return для печати x и y. Бонусные баллы за то, что не печатаются начальные и / или конечные нули.

0
ответ дан 18 December 2019 в 07:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: