简体   繁体   English

浮点到二进制值(C++)

[英]Floating Point to Binary Value(C++)

I want to take a floating point number in C++, like 2.25125, and a int array filled with the binary value that is used to store the float in memory (IEEE 754).我想在 C++ 中获取一个浮点数,如 2.25125,以及一个填充了用于将浮点数存储在内存中的二进制值的 int 数组(IEEE 754)。

So I could take a number, and end up with a int num[16] array with the binary value of the float: num[0] would be 1 num[1] would be 1 num[2] would be 0 num[3] would be 1 and so on...所以我可以取一个数字,最后得到一个 int num[16] 数组,其中包含浮点数的二进制值: num[0] 将是 1 num[1] 将是 1 num[2] 将是 0 num[3 ] 将是 1 等等...

Putting an int into an array isn't difficult, just the process of getting the binary value of a float is where I'm stuck.将 int 放入数组并不困难,只是获取浮点数的二进制值的过程是我卡住的地方。 Can you just read the binary in the memory that the float variable?你能在内存中读取浮点变量的二进制文件吗? If not, how could I go about doing this in C++?如果没有,我怎么能在 C++ 中做到这一点?

EDIT: The reason for doing the comparison this way is that I am wanting to learn to do bitwise operations in C++.编辑:以这种方式进行比较的原因是我想学习在 C++ 中进行按位运算。

Use union and bitset:使用 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;
}

It may not be an array but you can access bits with [] operator as if you were using an array.它可能不是数组,但您可以使用 [] 运算符访问位,就像使用数组一样。

Output输出

$ ./bits
01000000000100000001010001111011
BIT 4: 1
BIT 7: 0
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;

Explanation解释

(1 << i) shifts the value 1 , i bits to the left. (1 << i)将值1向左移动i位。 The & operator computes the bitwise and of the operands. &运算符计算操作数的按位和

The for loop runs once for each of the 32 bits in the float. for循环对浮点数中的 32 位中的每一个都运行一次。 Each time, i will be the number of the bit we want to extract the value from.每次, i将是我们想要从中提取值的位的编号。 We compute the bitwise and of the number and 1 << i :我们计算数字和1 << i的按位和:

Assume the number is: 1001011, and i = 2假设数字是:1001011,并且i = 2

1<<i will be equal to 0000100 1<<i将等于 0000100

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

if i = 3 then:如果i = 3则:

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

Basically, the result will be a number with i th bit set to the i th bit of the original number and all other bits are zero.基本上,结果将是一个数字,其中第i位设置为原始数字的第i位,所有其他位都为零。 The result will be either zero, which means the i th bit in the original number was zero or nonzero, which means the actual number had the i th bit equal to 1 .结果将是零,这意味着原始数字中的第i位为零或非零,这意味着实际数字的第i位等于1

other approach, using stl其他方法,使用 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;
}

If you need a particular floating point representation, you'll have to build that up semantically from the float itself, not by bit-copying.如果您需要特定的浮点表示,则必须从浮点本身在语义上构建它,而不是通过位复制。

c0x standard: http://c0x.coding-guidelines.com/5.2.4.2.2.html doesn't define the format of floating point numbers. c0x 标准: http ://c0x.coding-guidelines.com/5.2.4.2.2.html 没有定义浮点数的格式。

Can you just read the binary in the memory that the float variable?你能在内存中读取浮点变量的二进制文件吗?

Yes.是的。 Static cast a pointer to it to an int pointer and read the bits from the result.静态将指向它的指针转换为 int 指针并从结果中读取位。 An IEEE 754 float type in C++ is 32 bits. C++ 中的 IEEE 754 float类型是 32 位。

You can use an unsigned char to read the float byte by byte into the integer array:您可以使用无符号字符将浮点字节逐字节读入整数数组:

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.

By the way, if you just want to compare the bits (as you comment on another answer) use memcmp :顺便说一句,如果您只想比较这些位(当您评论另一个答案时),请使用memcmp

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

Looking at the comments in this answer ( Floating Point to Binary Value(C++) ) the reason to do this is to perform a bitwise comparison of two values.查看此答案中的注释( Floating Point to Binary Value(C++) ),这样做的原因是执行两个值的按位比较。

#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";


}

Cast the int pointer to a float pointer, and you're done.将 int 指针转换为浮点指针,就大功告成了。

(Though I wouldn't declare it as an int array. I'd use void* to make it clear the the memory is being used as a dumping ground for other values.) (虽然我不会将它声明为 int 数组。我会使用 void* 来明确表示内存被用作其他值的倾倒场。)

Incidentally, why don't you just use an array of floats?顺便说一句,为什么不直接使用浮点数数组呢?

Create a union of float and and unsigned long.创建 float 和 unsigned long 的联合。 set the value of the float member and iterate over the bits of the unsigned long value as already described in other answers.设置 float 成员的值并迭代 unsigned long 值的位,如其他答案中所述。

This will eliminate the cast operators.这将消除强制转换运算符。

You can do it with casting pointers as well.您也可以使用强制转换指针来实现。 Here is a little example这是一个小例子

#include <iostream>
#include <bitset>

using namespace std;

int main(){
    float f = 0.3f;
    int* p = (int*)&f;
    bitset<32> bits(*p);
    cout << bits << endl;
}

Well I don't believe C++ has any real safe way to store floats without some sort of issue.好吧,我不相信 C++ 有任何真正安全的方法来存储浮点数而不会出现某种问题。 When it comes to moving between machines and is both efficient and easily stored without using a large storage capacity.在机器之间移动时,既高效又易于存储,无需使用大存储容量。

It's very accurate, but it won't support really insane values.它非常准确,但它不会支持真正疯狂的值。 You will be able to have up to 7 digits in any location, but you can't exceed 7 digits on either side.您最多可以在任何位置拥有 7 位数字,但任何一侧都不能超过 7 位数字。 For the left you'll receive inaccurate results.对于左侧,您将收到不准确的结果。 On the right you'll get an error during read time.在右侧,您将在读取期间收到错误消息。 To resolve the error you can throw an error during the write or perform "buffer[idx++] & 0x7" on the read to prevent it from going outside 0 and 7 bounds.要解决该错误,您可以在写入期间抛出错误或在读取时执行“buffer[idx++] & 0x7”以防止其超出 0 和 7 边界。 Keep in mind "& 0x7" only works because it's a power of 2 minus one.请记住,“& 0x7”之所以有效,是因为它是 2 减 1 的幂。 Which is 2^3 - 1. You can only do that with those values Eg 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, etc...即 2^3 - 1。您只能使用这些值来执行此操作,例如 0、1、3、7、15、31、63、127、255、511、1023 等...

So it's up to you if you want to use this or not.因此,是否要使用它取决于您。 I felt it was a safe way to get most values you'll ever need.我觉得这是获得大多数你需要的价值的安全方式。 The example below shows how it's converted into a 4 byte array, but for C++ this would be a char*.下面的示例显示了如何将其转换为 4 字节数组,但对于 C++,这将是 char*。 If you don't want to perform division you can convert the POWERS_OF_TEN array into a secondary array with decimals and multiple instead.如果您不想执行除法,您可以将 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);
}

Here's my solution that doesn't give any warnings:这是我的解决方案,没有发出任何警告:

int32_t floatToIntBits(float f)
{
    char * c = (char*)&f;
    int32_t i = 0;
    i |= (int32_t)((c[3] << 24)     & 0xff000000);
    i |= (int32_t)((c[2] << 16)     & 0x00ff0000);
    i |= (int32_t)((c[1] << 8)      & 0x0000ff00);
    i |= (int32_t)((c[0])           & 0x000000ff);
    return i;
}

Easiest way:最简单的方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM