【问题标题】:Convert binary to hex value (32 bits)将二进制转换为十六进制值(32 位)
【发布时间】:2013-12-26 07:09:53
【问题描述】:

我正在尝试将二进制值转换为十六进制值,我得到了以下代码,它在 28 位上运行良好,但在 32 位上运行良好。

代码如下。

int main()
{
    long int longint=0;
    string buf;
    cin>>buf;
    int len=buf.size();
    for(int i=0;i<len;i++)
    {
        longint+=( buf[len-i-1]-48) * pow((double)2,i);
    }
    cout<<setbase(16);
    cout<<longint;
    return 0;
}

如果我输入 28 '1' (111111111111111111111111) 那么输出是 fffffff 但如果我输入 32 '1' (11111111111111111111111111111111) 则输出为 80000000。

谁能解释为什么会发生这种情况以及在上面的代码中为什么减去 48。

【问题讨论】:

  • 这是什么48?你假设ASCII?使用'0' 可能会更好。
  • 您使用哪个版本的编译器。尝试找出 long 它的大小,如果是 32 位,则第一位是符号位。也尝试使用 unsigned long int 作为 longint
  • unsigned long int 成功了 .. 谢谢 ..:).. 但它以小写字母 'af' 的形式出现,而应该是大写字母 'AF'。
  • 在输出数字之前使用 std::cout

标签: c++ binary hex


【解决方案1】:

如果我没记错的话,问题似乎出在pow 的使用上,它使用浮点数学。您可能遇到了溢出问题。

计算二的幂的更优雅的方法是使用位移:

2^0 = 1 << 0 = 1
2^1 = 1 << 1 = 2
2^2 = 1 << 2 = 4
2^n = 1 << n

【讨论】:

    【解决方案2】:

    您使用的是 int32,当您使用 32 字节时它超出范围,请尝试使用 int64,即 long long

        unsigned long long longint=0; //Change Here
        string buf;
        cin>>buf;
        int len=buf.length();
        for(int i=0;i<len;i++)
        {
            longint+=( buf[len-i-1]-48) * pow((double)2,i);
        }
        cout<<setbase(16);
        cout<<longint;
    

    【讨论】:

      【解决方案3】:

      正如 Nathan 的帖子,当您像这样更改代码时,它会显示正确,

      longint += (buf[len-i-1]-'0') << i;
      

      【讨论】:

        【解决方案4】:
        1. 这是因为您已强制将
          ( buf[len-i-1]-48) * pow((double)2,i)
          转换为 double

          double 是8个字节长,
          但是要存储额外的信息,
          不能充满代表0x80000000,
          你可以找到更多信息here

          和你的最后一个
          ( buf[len-i-1]-48) * pow((double)2,i)
          (当我是 31 岁时)表达式已经 溢出
          罢工> 但是从 4294967295.0000000(即 0xffffffff) 转换为 int 时发生了一些事情,它只是出来 0x80000000,但很抱歉我不知道为什么(请参考 TonyK 的评论)。
          你可以改成

          longint+=(long int)(( buf[len-i-1]-48) * pow(2,i));

        2. 为什么是负 48 ?
          因为 '0' 的 ascii 是 48,所以你想从文字 '0' 转换为数字 0,你必须这样做。

        【讨论】:

        • IEEE double 有一个 53 位尾数,足以将 0x80000000 存储到全精度。
        • 你说得对,真正的问题是如果我将 4294967295.0000000(实际上是 0xffffffff)转换为 int,它就变成了 0x80000000,而这部分超出了我的理解
        • 0xffffffff 超出了 32 位有符号整数的范围。如果你把它转换成 unsigned int,你应该得到 0xffffffff。
        【解决方案5】:

        原因是浮点值具有极限精度,而 pow() 计算机使用数值计算近似值,这不是绝对精确的。要获得精确值,您应该改用按位“>>”。

        您可以看到 pow() 函数的工作原理如下。

        我修改了你的代码

        longint+= ( buf[len-i-1]-48) * pow((double)2,i)

        到下面的代码,它是相等的,因为 pow() 返回一个双精度值。

        double temp = ( buf[len-i-1]-48) * pow((double)2,i);
        longint+= temp;
        cout<<setbase(16);
        cout<<"temp"<<endl;
        cout<<temp<<endl;
        cout<<longint<<endl;
        

        输出如下

        temp
        1.34218e+08
        fffffff
        temp
        2.68435e+08
        1fffffff
        temp
        5.36871e+08
        3fffffff
        temp
        1.07374e+09
        7fffffff
        temp
        2.14748e+09
        80000000
        final
        80000000
        

        这清楚地表明 pow() 的精度有限。 2.14748e+09 不等于 (2^31)。

        您应该使用最好的“>>”,或者只使用转换为不是 100% 正确的整数。

        你可以看到转换如下。

        当我改变时

        双倍温度 = ( buf[len-i-1]-48) * pow((double)2,i);

        int temp = ( buf[len-i-1]-48) * pow((double)2,i);

        结果是

        temp
        8000000
        fffffff
        temp
        10000000
        1fffffff
        temp
        20000000
        3fffffff
        temp
        40000000
        7fffffff
        temp
        80000000
        ffffffff
        final
        ffffffff
        

        哪个工作正常。

        减去 48 你从标准输入得到一个字符,例如,你从终端得到'1'而不是1。为了得到1。你应该使用'1'-'0'。 原因:计算机将'0'~'9'存储为一个带值的字节(48~57)。结果,'1' - '0' 等于 '1' - 48。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-05
          • 2012-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-26
          • 2011-04-30
          • 2014-05-20
          相关资源
          最近更新 更多