【问题标题】:Floating Point to Binary Value(C++)浮点到二进制值(C++)
【发布时间】:2010-10-03 04:57:24
【问题描述】:

我想在 C++ 中获取一个浮点数,例如 2.25125,以及一个填充了二进制值的 int 数组,该二进制值用于将浮点数存储在内存中 (IEEE 754)。

所以我可以取一个数字,最后得到一个带有浮点二进制值的 int num[16] 数组: num[0] 将是 1 num[1] 将是 1 num[2] 将是 0 num[3] 将是 1 等等……

将 int 放入数组并不困难,只是获取浮点数的二进制值的过程是我遇到的问题。你可以只读取内存中浮点变量的二进制文件吗?如果没有,我怎么能在 C++ 中做到这一点?

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

【问题讨论】:

  • 出于好奇 - 为什么您需要一位整数?

标签: c++ binary floating-point ieee-754


【解决方案1】:
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 &lt;&lt; i) 将值1i 向左移动位。 &amp; 运算符计算操作数的 按位与

for 循环对浮点数中的 32 位中的每一个运行一次。每次,i 将是我们要从中提取值的位数。我们计算数字和1 &lt;&lt; i的按位与:

假设号码是:1001011,i = 2

1&lt;&lt;i 将等于 0000100

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

如果i = 3 那么:

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

基本上,结果将是一个数字,其中ith 位设置为原始数字的ith 位,所有其他位为零。结果将为零,这意味着原始数字中的ith 位为零或非零,这意味着实际数字的ith 位等于1

【讨论】:

  • 这不是他想要的:二进制表示必须是大小为sizeof(float) * CHAR_BIT (-1) 的数组
  • @Christoph:我怀疑。看问题。他说他想要一个 int 数组中浮点数的二进制表示。
  • 他希望 int 数组包含位模式,即每个位一个 int - 因此,它的大小必须是浮点变量中的位数,即 32(他错误地假设浮点值需要 16 位...)
  • Mehrdad,有什么理由在这里使用几乎不推荐使用的 C 样式转换而不是推荐的 reinterpret_cast?人们几乎一致认为,永远不应该使用 C 风格的转换——尤其是在“教科书”示例中。
  • @Konrad,它更短:) 我回答的唯一目的是 for 循环中的行。我不想用不必要的最佳实践来混淆答案。
【解决方案2】:

将 int 指针转换为浮点指针,就完成了。

(虽然我不会将它声明为 int 数组。我会使用 void* 来明确表示内存被用作其他值的转储场。)

顺便说一句,你为什么不直接使用浮点数组?

【讨论】:

    【解决方案3】:

    如果您需要特定的浮点表示,则必须从浮点本身进行语义构建,而不是通过位复制。

    c0x 标准: http://c0x.coding-guidelines.com/5.2.4.2.2.html 没有定义浮点数的格式。

    【讨论】:

      【解决方案4】:

      你可以只读取内存中浮点变量的二进制文件吗?

      是的。静态将指向它的指针转换为 int 指针并从结果中读取位。 C++ 中的 IEEE 754 float 类型是 32 位。

      【讨论】:

        【解决方案5】:

        创建一个 float 和 unsigned long 的联合。设置 float 成员的值并遍历 unsigned long 值的位,如其他答案中所述。

        这将消除强制转换运算符。

        【讨论】:

          【解决方案6】:

          您可以使用无符号字符将浮点数逐字节读入整数数组:

          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】:

            使用 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: C++ NOT 规范使用 ieee754(可以)。 Long 被 NOT 指定为 32 位(必须至少为 32)。这永远不会是可移植的,因为分配给联合中的一个字段并从另一个字段读取是未指定的行为。如果我对上述任何一项都不正确,请告诉我 C++ 标准中定义它的子句,因为简单的搜索显示这两个语句都是错误的。
            • @deft_code 不仅如此,“ieee754 浮点数始终为 32 位”也是错误的。重新阅读标准并注意其中指定的 3 种类型,然后考虑删除您的评论。
            • 这是 UB。请永远不要这样做。
            • @MichalŠtein 其实现定义的行为。这种技术在 C 代码中大量使用,并且为了向后兼容(在设计新功能时 C++ 考虑的一个非常重要的部分)需要在 C++ 中工作。
            【解决方案8】:

            查看此答案 (Floating Point to Binary Value(C++)) 中的 cmets,这样做的原因是对两个值进行按位比较。

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

            【讨论】:

              【解决方案9】:

              最简单的方法:

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

              【讨论】:

                【解决方案10】:

                好吧,我不相信 C++ 有任何真正安全的方式来存储浮点数而不会出现某种问题。在机器之间移动时,既高效又易于存储,无需使用大存储容量。

                它非常准确,但它不支持真正疯狂的值。在任何位置,您最多可以有 7 位数字,但两边不能超过 7 位数字。对于左侧,您将收到不准确的结果。在右侧,您会在读取期间收到错误消息。要解决该错误,您可以在写入期间抛出错误或在读取时执行“buffer[idx++] & 0x7”,以防止其超出 0 和 7 范围。请记住,“& 0x7”仅有效,因为它是 2 减 1 的幂。即 2^3 - 1。您只能使用这些值来执行此操作,例如0、1、3、7、15、31、63、127、255、511、1023等……

                因此,是否要使用它取决于您。我觉得这是获得您所需要的大多数价值的安全方式。下面的示例显示了如何将其转换为 4 字节数组,但对于 C++,这将是一个 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】:

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

                  【讨论】:

                    【解决方案12】:

                    您也可以使用强制转换指针来做到这一点。这是一个小例子

                    #include <iostream>
                    #include <bitset>
                    
                    using namespace std;
                    
                    int main(){
                        float f = 0.3f;
                        int* p = (int*)&f;
                        bitset<32> bits(*p);
                        cout << bits << endl;
                    }
                    

                    【讨论】:

                      【解决方案13】:

                      这是我没有给出任何警告的解决方案:

                      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;
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-09-10
                        • 1970-01-01
                        • 2015-01-25
                        • 1970-01-01
                        • 1970-01-01
                        • 2015-06-01
                        相关资源
                        最近更新 更多