浮点数转二进制值(C++)

21

我想在C++中处理一个浮点数,例如2.25125,并且有一个整型数组,里面填充了存储浮点数的二进制值(IEEE 754)。

因此,我可以输入一个数字,最终得到一个由16个整数组成的num数组,其中包含浮点数的二进制值: num[0]应为1 num[1]应为1 num[2]应为0 num[3]应为1 以此类推...

将整数放入数组中并不困难,仅在获取浮点数的二进制值的过程中遇到了麻烦。在C++中,您是否可以直接读取浮点变量所在内存中的二进制值?如果不行,我该如何实现这一点?

编辑:使用此种方式进行比较的原因是我想学习在C++中进行位运算。


2
出于好奇 - 为什么您需要每个位一个整数? - user3458
14个回答

32

使用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

ieee754浮点数始终为32位,C++规定使用ieee754作为其浮点类型。 Long也被规定为32位。将联合更改为使用long而不是int,您将拥有真正的可移植代码。 - deft_code
9
@deft_code说:C++并没有规定必须使用ieee754(但可以使用)。long也没有规定必须是32位(至少要有32位)。将一个联合体中的一个字段赋值,然后读取另一个字段是未指定的行为,因此这种写法不具备可移植性。如果我上述任何一点有误,请告诉我在C++标准中定义它们的条款,因为简单的搜索结果表明这两个语句都是错误的。 - Martin York
@deft_code 不仅如此,"ieee754浮点数总是32位"也是错误的。请重新阅读标准并注意那里指定的3种类型,然后考虑删除您的评论。 - underscore_d
@MichalŠtein 这是实现定义行为。这种技术在C代码中被广泛使用,并且对于向后兼容性(在设计新功能时考虑的一个非常重要部分)需要在C++中起作用。 - Martin York
@MatrinYork 这是C++中的未定义行为。 - DexterHaxxor
显示剩余2条评论

15
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位设置为原始数字的第i位,所有其他位都为零。 结果要么为零,这意味着原始数字中的第i位为零,要么为非零,这意味着实际数字的第i位等于1


1
他希望int数组包含位模式,即每个位对应一个int - 因此,它的大小必须是float变量中的位数,即32(他错误地认为float值占用16位...) - Christoph
六个字母的变量名,这太荒谬了...它是语言规范的一部分,代表char类型的位数。接下来我们考虑避免使用sizeof吧... - Johannes Schaub - litb
我指出了与CHAR_BIT无关的对他最初问题的帮助不大的副讨论... - user7116
1
Mehrdad,你在这里使用已经被淘汰的C风格转换而不是推荐的reinterpret_cast,有什么原因吗?几乎所有人都认为不应该使用C风格转换 - 尤其不是在“教科书”示例中。 - Konrad Rudolph
2
@Konrad,这更简短 :) 我回答的唯一目的是for循环中的那一行。我不想用不必要的最佳实践来混淆答案。 - Mehrdad Afshari
显示剩余12条评论

7

另一种方法是使用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;
}

3
你可以直接读取存储浮点变量的内存中的二进制吗?
可以。将其指针静态转换为int指针并从结果中读取位。在C++中,IEEE 754的float类型为32位。

2

2
您可以使用unsigned char将float按字节读入整数数组中:
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));

2

通过查看这个答案中的评论(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";


}

1
将int指针转换为float指针,问题就解决了。
(虽然我不会将其声明为int数组。我会使用void*来明确表明内存被用作其他值的垃圾场。)
顺便说一句,为什么不直接使用float数组呢?

1
创建一个浮点数和无符号长整型的联合体。设置浮点成员的值并按照其他答案中已经描述的方式迭代无符号长整型值的位。
这将消除强制转换运算符。

1
你也可以使用指针转换来完成。以下是一个简单的示例。
#include <iostream>
#include <bitset>

using namespace std;

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接