Плавающая точка для двоичного значения (С++)
Я хочу взять число с плавающей запятой в С++, например, 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: причина такого сравнения заключается в том, что я хочу научиться выполнять побитовые операции на С++.
Ответы
Ответ 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));