Need Fastest Way to Convert 2'S Complement to Decimal in C

I have a certain 18 bits (which are in 2's complement) within 32 bits. I need to convert them to decimal. Please show me a code snippet in C.

2

3 Answers

First you need to do sign extension on your 18 bits, to fill out the native int:

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

if (negative)
  nativeInt = smallInt | ~((1 << 18) - 1);
else
  nativeInt = smallInt;

If the number is considered negative (i.e. bit 17 is set), we bitwise-or it with a bit pattern that has ones in all the remaining bits. This creates the proper negative native-sized integer.

Then just print the native integer as usual, since you sound as if you need a decimal string representation:

char buf[12];

snprintf(buf, sizeof buf, "%d", nativeInt);

Of course, this last part might not at all match your expectaions; it's not perhaps "fastest". Since you have a limited input range of 18 bits, it's probably possible to come up with something a bit more optimized.

A few ideas:

  1. Remove the buffer size argument (i.e. use sprintf()) since we can be quite sure about the maximum number of characters needed.
  2. Since we know the range, use something less general that never checks for values outside the range.
  3. Use itoa() if you have it, less general than s*printf() so might be faster.
1

I've tried this myself and works just fine:

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

Sample:

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

Results in

decimal = -127

Here is the code snippet for 16-bit numbers. A similar approach should work for other bit depths. However, I cannot ensure that this is the fastest snippet.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

James H. Sterling

James H. Sterling

Environmental Science & Climate Journalist

James Sterling reports on renewable energy developments, climate policy, ecological conservation, and green tech innovations around the globe.

Share this article
Twitter Facebook Pinterest