Как вы выводите двоичное представление чисел? - PullRequest
2 голосов
/ 03 октября 2010

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

union ufloat {
  float f;
  unsigned u
};

ufloat u1;
u1.f = 0.3f;

Чего я не понимаю, так это как работает.Что делает часть 0.3?Я не мог найти это в моем тексте.И как это конвертировать поплавок в двоичный файл?Потому что cout<<u1.u;, похоже, не дает мне ответа.Может кто-нибудь помочь?

Ответы [ 3 ]

3 голосов
/ 03 октября 2010

0.3 это просто тестовое значение.Печать u1.u не даст вам двоичное представление, но значение двоичного представления интерпретируется как целое число из 10 оснований.Чтобы получить двоичное значение, вам нужно преобразовать u1.u в двоичное.

Еще один способ преобразования - использовать побитовые операторы .

Например:

unsigned x = 11;
do
{
    cout << (x & 1); // print last bit
    x = x >> 1; // get rid of the printed bit
} while ( x );

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

Я также предлагаю вам прочитать о союзах .По сути, unsigned будет занимать то же пространство памяти, что и float, что позволит вам обойти ограничения использования побитовых операторов для поиска двоичного представления float.

2 голосов
/ 03 октября 2010

Быть чрезмерно педантичным, это недопустимо в C или C ++.

Я подозреваю, что каждый существующий компилятор поддерживает его, но для стандарта недопустимо писать один член объединения, а затем читать другой. Однако даже если вы знаете, что float и unsigned имеют одинаковый размер, вы уже используете некоторую информацию, определяемую реализацией, так что вы можете также использовать больше. Это распространено и обычно работает.

Для справки, вы всегда можете исследовать память как последовательность байтов:

#include <iostream>
#include <iomanip>
#include <climits>
#include <cassert>

int main() {
    float f = 0.3;
    unsigned char *buf = (unsigned char*)(&f);

    // Now we just have to print the sucker.

    assert(CHAR_BIT == 8); // otherwise hex isn't much use

    // This shows the byte representation, low addresses on the left.
    // On a little-endian machine, you might like to count down for 
    // convenience of reading.
    for (int i = 0; i < sizeof f; ++i) {
        std::cout << std::hex << std::setw(2) << std::setfill('0');
        std::cout << static_cast<unsigned int>(buf[i]) << ' ';
    }
    std::cout << '\n';
}

Вывод (на моей машине):

9a 99 99 3e

Если вы предпочитаете использовать unsigned вместо unsigned char:

#include <cstring>

float f = 0.3;
unsigned u;
assert(sizeof f == sizeof u);
std::memcpy(&u, &f, sizeof f);

std::cout << std::hex << u << "\n";

Вывод (на моей машине):

3e99999a
2 голосов
/ 03 октября 2010

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

Когда вы обращаетесь к области памяти через элемент данных u, программа считает, что вы хотите представить область памяти в виде двоичного целого числа, а не значения с плавающей запятой.Но поскольку область памяти фактически хранит значение с плавающей запятой (0.3f), оно просто выводит это значение, как если бы оно было двоичным целым числом.Таким образом, вы получите двоичное представление числа с плавающей запятой.

...