2015-08-27 2 views
2

Скажем, у нас есть двойной, скажем, x = 4.3241;Получите точное битовое представление двойника, в C++

Проще говоря, я хотел бы знать, как в C++ можно просто получить int для каждый бит в представлении числа?

Я видел другие questions и читал страницу на bitset, но, боюсь, я до сих пор не понимаю, как получить эти биты.

Так, например, хотелось бы вход, чтобы быть x = 4.53, а если бит представление было 10010101, то я хотел бы 8 Интс, каждый из которых представляет каждый 1 или 0.

ответ

5

Что-то вроде:

double doubleValue = ...whatever...; 
uint8_t *bytePointer = (uint8_t *)&doubleValue; 

for(size_t index = 0; index < sizeof(double); index++) 
{ 
    uint8_t byte = bytePointer[index]; 

    for(int bit = 0; bit < 8; bit++) 
    { 
     printf("%d", byte&1); 
     byte >>= 1; 
    } 
} 

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

Просто выделите массив и сохраните бит вместо их печати.

(предположение сделано: что есть восемь битов в байте; технически не гарантируется в C, но достаточно надежные на любом оборудовании, вы, вероятно, столкнуться в настоящее время)

+0

Это будет печатать байты от наиболее значимого до наименьшего по одному от наименее значимого бита до максимального. Я не уверен, что этот порядок имеет смысл. –

+1

Какой заказ _does_ имеет смысл? Существует причина, по которой существуют проблемы с контентом. Весь выбор представления довольно произволен. Здесь речь идет о _accessing_ бит, и, хотя я думаю, что другие приказы будут более удачными, на самом деле это зависит от OP, чтобы решить эти последующие варианты. – sehe

+1

Да, и я считаю, что это следует упомянуть, поскольку OP может не обращать внимания на эту концепцию. –

2

Это очень зависит от архитектуры. После сбора следующей информации

  1. Endianess вашей целевой архитектуры
  2. представление с плавающей точкой (например IEEE754)
  3. Размера вашего double типа

вы должны быть в состоянии получить которое вы ищете. Пример испытания на системе x86_64

#include <iostream> 
#include <climits> 

int main() 
{ 
    double v = 72.4; 

    // Boilerplate to circumvent the fact bitwise operators can't be applied to double 
    union { 
    double value; 
    char array[sizeof(double)]; 
    }; 

    value = v; 

    for (int i = 0; i < sizeof(double) * CHAR_BIT; ++i) { 
    int relativeToByte = i % CHAR_BIT; 
    bool isBitSet = (array[sizeof(double) - 1 - i/CHAR_BIT] & 
     (1 << (CHAR_BIT - relativeToByte - 1))) == (1 << (CHAR_BIT - relativeToByte - 1)); 
    std::cout << (isBitSet ? "1" : "0"); 
    } 
    return 0; 
} 

Live Example

Выход

0100000001010010000110011001100110011001100110011001100110011010 

, который разделен на sign, exponent и significand (или мантиссы), является

0 10000000101 (1.)0010000110011001100110011001100110011001100110011010 

enter image description here (Изображение взято из wikipedia)

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

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

double v = 72.4; 

uint8_t *array = reinterpret_cast<uint8_t*>(&v); 

for (int i = 0; i < sizeof(double); ++i) { 
    uint8_t byte = array[i]; 
    for (int bit = CHAR_BIT - 1; bit >= 0; --bit) // Print each byte 
    std::cout << ((byte & (1 << bit)) == (1 << bit)); 
} 

Приведенный выше код будет просто печатать каждый байт из одного в нижнем обращении к одному с высшим адрес.


Edit: так как кажется, что вы просто заинтересованы в том, сколько 1s и 0s есть (т.е. порядок полностью не имеет значения), в данном конкретном случае я согласен с другими ответами, и я бы тоже просто перейдите к счетному решению

uint8_t *array = reinterpret_cast<uint8_t*>(&v); 

for (int i = 0; i < sizeof(double); ++i) { 
    uint8_t byte = array[i]; 
    for (int j = 0; j < CHAR_BIT; ++j) { 
    std::cout << (byte & 0x1); 
    byte >>= 1; 
    } 
} 
+0

Привет, Марко, спасибо за этот подробный ответ. Честно говоря, моя главная мотивация заключалась в том, чтобы суммировать эти ints, чтобы я мог сделать хеш-функцию, идущую от удвоений до size_t. В этом смысле порядок не имеет значения. Тем не менее, мне было бы любопытно, как вы это сделаете, если заказ действительно имеет значение. – Spacey

+0

@ Learnaholic С учетом этого специфического требования (которое бы сильно изменило ситуацию) я могу только подтвердить, что просто проверка каждого бита - правильный путь (игнорируя их порядок или внутреннее представление). Я не могу не заметить, что хеширование может быть ** не лучшим решением для значений с плавающей запятой. Причина в том, что сравнение плавающих точек для равенства является сложным, поэтому может быть результатом их хэширования. Даже не внося в игру ненормальные данные, хеширование значений с плавающей запятой с побитовым тестом по-прежнему является плохой идеей из-за потенциально перекрывающихся шаблонов. –

+0

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