Подтвердить что ты не робот

Плавающая точка для двоичного значения (С++)

Я хочу взять число с плавающей запятой в С++, например, 2.25125, и массив int, заполненный двоичным значением, которое используется для хранения float в памяти (IEEE 754).

Поэтому я мог бы взять число и в итоге получить массив int num [16] с двоичным значением float: num [0] будет 1 num [1] будет 1 num [2] будет 0 num [3] будет 1 и так далее...

Помещение int в массив не сложно, просто процесс получения двоичного значения float - это место, где я застрял. Можете ли вы просто прочитать двоичный файл в памяти, который имеет переменную float? Если нет, как я могу сделать это на С++?

EDIT: причина такого сравнения заключается в том, что я хочу научиться выполнять побитовые операции на С++.

4b9b3361

Ответ 1

Используйте union и bitset:

#include <iostream>
#include <bitset>
#include <climits>

int main()
{
    union
    {
        float input; // assumes sizeof(float) == sizeof(int)
        int   output;
    } data;

    data.input = 2.25125;

    std::bitset<sizeof(float) * CHAR_BIT> bits(data.output);
    std::cout << bits << std::endl;

    // or
    std::cout << "BIT 4: " << bits[4] << std::endl;
    std::cout << "BIT 7: " << bits[7] << std::endl;
}

Возможно, это не массив, но вы можете получить доступ к битам с помощью оператора [], как если бы вы использовали массив.

Выход

$ ./bits
01000000000100000001010001111011
BIT 4: 1
BIT 7: 0

Ответ 2

int fl = *(int*)&floatVar; //assuming sizeof(int) = sizeof(float)

int binaryRepresentation[sizeof(float) * 8];

for (int i = 0; i < sizeof(float) * 8; ++i)
    binaryRepresentation[i] = ((1 << i) & fl) != 0 ? 1 : 0;

Описание

(1 << i) сдвигает значения бит 1, i влево. Оператор & вычисляет побитовый и операндов.

Цикл for выполняется один раз для каждого из 32 бит в поплавке. Каждый раз i будет номером бит, из которого мы хотим извлечь значение. Мы вычисляем поразрядное число и 1 << i:

Предположим, что число: 1001011 и i = 2

1<<i будет равно 0000100

  10001011
& 00000100
==========
  00000000

если i = 3, то:

  10001011
& 00001000
==========
  00001000

В принципе, результатом будет число с i th бит, установленным на i -й бит исходного номера, а все остальные биты равны нулю. Результат будет либо нулевым, что означает, что бит i th в исходном номере был нулевым или ненулевым, что означает, что фактическое число имеет бит i th, равный 1.

Ответ 3

другой подход, используя stl

#include <iostream>
#include <bitset>

using namespace std;
int main()
{
    float f=4.5f;
    cout<<bitset<sizeof f*8>(*(long unsigned int*)(&f))<<endl;
    return 0;
}

Ответ 4

Если вам требуется конкретное представление с плавающей запятой, вам придется строить семантически это из самого поплавка, а не по битовому копированию.

Стандарт c0x: http://c0x.coding-guidelines.com/5.2.4.2.2.html не определяет формат чисел с плавающей запятой.

Ответ 5

Можете ли вы просто прочитать двоичный файл в памяти, который имеет переменную float?

Да. Static отбрасывает указатель на указатель int и считывает бит из результата. Тип IEEE 754 float в С++ - 32 бита.

Ответ 6

Вы можете использовать unsigned char для чтения байта побайта по байту в целочисленный массив:

unsigned int bits[sizeof (float) * CHAR_BIT];
unsigned char const *c = static_cast<unsigned char const*>(
    static_cast<void const*>(&my_float)
);

for(size_t i = 0; i < sizeof(float) * CHAR_BIT; i++) {
    int bitnr = i % CHAR_BIT;
    bits[i] = (*c >> bitnr) & 1;
    if(bitnr == CHAR_BIT-1)
        c++;
}

// the bits are now stored in "bits". one bit in one integer.

Кстати, если вы просто хотите сравнить бит (как вы комментируете другой ответ), используйте memcmp:

memcmp(&float1, &float2, sizeof (float));

Ответ 7

Глядя на комментарии в этом ответе (Плавающая точка на двоичное значение (С++)), причина в том, чтобы выполнить поразрядное сравнение двух значений.

#include <iostream>

int main()
{
    union Flip
    {
         float input;   // assumes sizeof(float) == sizeof(int)
         int   output;
    };

    Flip    data1;
    Flip    data2;
    Flip    data3;

    data1.input = 2.25125;
    data2.input = 2.25126;
    data3.input = 2.25125;

    bool    test12  = data1.output ^ data2.output;
    bool    test13  = data1.output ^ data3.output;
    bool    test23  = data2.output ^ data3.output;

    std::cout << "T1(" << test12 << ") T2(" << test13 << ") T3(" << test23 << ")\n";


}

Ответ 8

Переместите указатель int на указатель с плавающей точкой, и все готово.

(Хотя я бы не объявлял его как массив int. Я бы использовал void *, чтобы очистить память, используемую как свалку для других значений.)

Кстати, почему бы вам просто не использовать массив поплавков?

Ответ 9

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

Это приведет к устранению операторов трансляции.

Ответ 10

Ну, я не верю, что у С++ есть реальный безопасный способ хранения поплавков без какой-либо проблемы. Когда дело доходит до перехода между машинами, оно эффективно и легко сохраняется без использования большой емкости.

Это очень точно, но он не будет поддерживать действительно безумные ценности. Вы сможете иметь до 7 цифр в любом месте, но вы не можете превышать 7 цифр с каждой стороны. Слева вы получите неточные результаты. Справа вы получите сообщение об ошибке во время чтения. Чтобы устранить эту ошибку, вы можете сбросить ошибку во время записи или выполнить "чтение [idx ++] и 0x7" в read, чтобы предотвратить ее выход за пределы 0 и 7. Имейте в виду, что "& 0x7" работает только потому, что он имеет мощность 2 минус один. Это 2 ^ 3 - 1. Вы можете сделать это только с этими значениями. 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023 и т.д.

Итак, это зависит от вас, если вы хотите использовать это или нет. Я чувствовал, что это безопасный способ получить большинство ценностей, которые вам понадобятся. В приведенном ниже примере показано, как он преобразуется в 4-байтовый массив, но для С++ это будет char *. Если вы не хотите выполнять деление, вы можете преобразовать массив POWERS_OF_TEN во вторичный массив с десятичными знаками и несколькими.

const float CacheReader::POWERS_OF_TEN[] = 
{
    1.0F, 10.0F, 100.0F, 1000.0F, 10000.0F, 100000.0F, 1000000.0F, 10000000.0F
};

float CacheReader::readFloat(void)
{
    int flags = readUnsignedByte();
    int value = readUnsignedTriByte();
    if (flags & 0x1)
        value = -value;
    return value / POWERS_OF_TEN[(flags >> 1) & 0x7];
}

unsigned __int32 CacheReader::readUnsignedTriByte(void)
{
    return (readUnsignedByte() << 16) | (readUnsignedByte() << 8) | (readUnsignedByte());
}

unsigned __int8 CacheReader::readUnsignedByte(void)
{
    return buffer[reader_position] & 0xFF;
}

void CacheReader::writeFloat(float data)
{
    int exponent = -1;
    float ceiling = 0.0F;

    for ( ; ++exponent < 8; )
    {
        ceiling = (POWERS_OF_TEN[exponent] * data);
        if (ceiling == (int)ceiling)
            break;
    }

    exponent = exponent << 0x1;
    int ceil = (int)ceiling;
    if (ceil < 0)
    {
        exponent |= 0x1;
        ceil = -ceil;
    }
    buffer[writer_position++] = (signed __int16)(exponent);
    buffer[writer_position++] = (signed __int16)(ceil >> 16);
    buffer[writer_position++] = (signed __int16)(ceil >> 8);
    buffer[writer_position++] = (signed __int16)(ceil);
}

Ответ 11

Самый простой способ:

float myfloat;
file.read((char*)(&myfloat),sizeof(float));