需要最快的方法将C中的二进制补码转换为十进制

4

我有32位中的18位(采用二进制补码表示),需要将它们转换成十进制。请给我提供一个C语言代码片段。


当您说“decimal”时,您是指将数字以文本形式打印为10进制,对吗? - Mads Elvheim
@MadsElvheim,肯定一个十进制数意味着“以10为基数”。 - Box Box Box Box
3个回答

10

首先,您需要对18位进行符号扩展,以填充本机int

const int negative = (smallInt & (1 << 17)) != 0;
int nativeInt;

if (negative)
  nativeInt = smallInt | ~((1 << 18) - 1);
else
  nativeInt = smallInt;
如果这个数被认为是负数(即第17位被设置),我们将其与一个在所有剩余位上都有1的位模式进行按位或运算。这将创建适当的负本地大小整数。
然后,只需像往常一样打印本地整数,因为您似乎需要一个十进制字符串表示:
char buf[12];

snprintf(buf, sizeof buf, "%d", nativeInt);
当然,最后一部分可能与您的期望完全不符,它可能并不是“最快”的。由于您的输入范围仅为18位,可能可以想出更加优化的方法。
几个想法:
1. 删除缓冲区大小参数(即使用`sprintf()`),因为我们对所需的最大字符数非常确定。 2. 由于我们知道该范围,使用某些不那么通用的内容,永远不会检查范围外的值。 3. 如果有`itoa()`,则使用它,比`s*printf()`不太通用,因此可能更快。

1
符号扩展:if (smallInt >= (1 << 17)) smallInt -= (1 << 18);。当然,前提是smallInt在正确的范围内,并且未使用的高位为0。 - Steve Jessop

1

这里是16位数字的代码片段。类似的方法也适用于其他位深度。但是,我不能保证这是最快的代码片段。

int16_t twosCompToDec(uint16_t two_compliment_val)
{
    // [0x0000; 0x7FFF] corresponds to [0; 32,767]
    // [0x8000; 0xFFFF] corresponds to [-32,768; -1]
    // int16_t has the range [-32,768; 32,767]

    uint16_t sign_mask = 0x8000;

    // if positive
    if ( (two_compliment_val & sign_mask) == 0 ) {
        return two_compliment_val;
    //  if negative
    } else {
        // invert all bits, add one, and make negative
        return -(~two_compliment_val + 1);
    }
}

0

我自己尝试过,效果非常好:

int binTwosComplementToSignedDecimal(char binary[],int significantBits) 
{
    int power = pow(2,significantBits-1);
    int sum = 0;
    int i;

    for (i=0; i<significantBits; ++i)
    {
        if ( i==0 && binary[i]!='0')
        {
            sum = power * -1;
        }
        else 
        {
            sum += (binary[i]-'0')*power;//The -0 is needed
        }
        power /= 2;
    }

    return sum;
}

示例:

char binary[8] = '10000001';
int significantBits = 8;
int decimal = binTwosComplementToSignedDecimal(binary,significantBits);

结果为

decimal = -127

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