【问题标题】:Converting two's complement output to signed decimal将二进制补码输出转换为有符号十进制
【发布时间】:2014-05-21 16:48:00
【问题描述】:

如果这个问题已经得到回答,但我无法找到我要找的东西,我深表歉意。

我正在使用 SPI 设备在 c++ 中工作。 SPI 设备以 2 的补码形式以 16 位字输出数据。我正在尝试将此数据转换为十进制以用于过滤器。

我附上了一些示例代码,要求用户输入一个二进制补码的数字,然后输出带符号的十进制版本。

#include <iostream>     
#include <stdlib.h>
#include <cstdint>
#include <cmath>
#include <bitset>
using std::cout;
using std::endl;
using std::cin;
using std::hex;
using std::dec;
using std::bitset;
int main () {
    uint16_t x2=0;
    cout<<"Please enter the number you would like to convert from 2's complement.  "<<endl;
    cin>>x2;
    int diff=0x0000-x2;
    cout<<"The number you have entered is: "<<dec<<diff<<endl;
return 0;
}

当我运行这个程序并输入类似 0x3B4A 的内容时,它总是输出 0。我不完全确定发生了什么,而且我对 c++ 很陌生,所以如果这是一个愚蠢的问题,请原谅。另外,请忽略标题中的任何额外内容。这是一个大型项目的一部分,我不记得标头的哪些部分与这段特定的代码部分有关。

谢谢!

编辑:这主要是给本的。在阅读了您最近的评论后,我做了以下更改,但我仍然只是得到了我输入的十六进制数的十进制数

#include <iostream>     
#include <stdlib.h>
#include <cstdint>
#include <cmath>
#include <bitset>
using std::cout;
using std::endl;
using std::cin;
using std::hex;
using std::dec;
using std::bitset;
int main () {
    int16_t x2=0;
    cout<<"Please enter the number you would like to convert from 2's complement.  "<<endl;
    cin>>hex>>x2;
    int flags= (x2>>14) & 3;
    int16_t value=(x2 << 2) >> 2;
    cout<<"The number you have entered is: "<<dec<<value<<endl;
return 0;
}

【问题讨论】:

  • “转换”是解析的一部分。这个0x0000-x2 没有任何帮助。

标签: c++ decimal hex twos-complement


【解决方案1】:

我不确定 OP 的问题是否有必要,但对于任何正在寻找将 16 位 2 的补码无符号整数转换为有符号整数的公式的人,我认为它的一个变体看起来像这样(对于输入val):

(0x8000&val ? (int)(0x7FFF&val)-0x8000 : val)

这相当于:

  • 如果第一位是 1,则它是一个负数,所有其他位都在 2 的补码中
  • 通过减去 0x8000 提取负部分
  • 否则低位只是正整数值

将它包装在一个函数中并进行一些基本的错误检查可能是一个好主意(也可以强制输入实际上是一个无符号的 16 位整数)。

【讨论】:

    【解决方案2】:

    标准库函数strtol 将字符串输入转换为数字,并且只要您将0 作为基数参数传递,就支持0x 前缀。

    由于int16_t 几乎可以肯定是 16 位二进制补码符号,因此您可以直接使用它。

    【讨论】:

    • Ben,我尝试使用 int16_t 并删除 0x000-x2 但是,我仍然得到与以前相同的结果。您能否详细说明这将如何工作。此外,即使我们确实让它工作,我也可以预见到一些麻烦,因为设备将输出一个 16 位字,但二进制补码仅包含在位 0-13 中,因为位 15 和 14 是标志。
    • @user:那么您应该取消标记:flags = (input &gt;&gt; 14) &amp; 3 并将符号位从第 13 位传播到第 14 位和第 15 位,以形成完整的 16 位二进制补码:value = (input &lt;&lt; 2) &gt;&gt; 2跨度>
    • Ben,我尝试过实现这一点(请参阅我原始问题中添加的代码);但是,我仍然只是获取十六进制输入的值。也就是说,输入 0x3b4a(应该是 -1206 的 14 位 2 的补码)输出 15178。
    • @andrew:在换班之前把它放在一个 int16_t 中
    • 非常感谢您继续回复本。我认为我已经通过将x2 初始化为int16_t 将值存储在int16_t 中。不是这样吗?
    【解决方案3】:

    您要求 cin 读取为十进制(不进行格式更改),因此一旦读取不是 0-9 数字的 x,它就会停止,留下零。

    只需将 hex 添加到您的 cin 行:cin &gt;&gt; hex &gt;&gt; x2;

    【讨论】:

    • 谢谢,马克。我做了这个更正,现在我可以成功输入一个十六进制数;但是,我似乎仍然无法获得正确的转换。例如,当我输入 Ox3B4A 时,我现在得到 -15178 的输出;但是,根据我对二进制补码的理解,这个值应该对应于 -1206。您对为什么会发生这种情况有任何想法吗?基本上,我相信我正在做的是找到数字 0x3b4a 的补码,然后它应该只是数字的十进制值的十六进制等价物。
    • 现在,我知道了另一种可以正确转换的方法,方法是使用以下公式。 dec=-a_(n-1)*2^(n-1)+sum(a_(i)*2^i)_(i=0)^(n-2) 其中n是二进制表示的长度二进制补码,a_i 是二进制表示的第 i^(th) 项,全部以松散的乳胶格式编写。我没有使用这种转换的原因是因为有人告诉我它与其他方法相比会非常慢,而且我需要它的应用程序需要运行得非常快(再次因为它被过滤器使用)。再次感谢!
    • 谢谢,Mark,Ben 能够帮助我完成剩下的工作,但您的回答是重要的第一步!如果我可以投票给你的答案,我会的。
    猜你喜欢
    • 2011-09-03
    • 2014-11-15
    • 2013-09-28
    • 2020-04-29
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    相关资源
    最近更新 更多