7

I'm wondering if there's a way to do a two's complement sign extension as you would in C/C++ in Python, using standard libraries (preferably on a bitarray).

C/C++:

// Example program
#include <iostream>
#include <string>

int main()
{
    int x = 0xFF;
    x <<= (32 - 8);
    x >>= (32 - 8);
    std::cout << x;
    return 0;
}

And here's a Python function I've written which (in my testing) accomplishes the same thing. I'm simply wondering if there's a built-in (or just faster) way of doing it:

def sign_extend(value, bits):
    highest_bit_mask = 1 << (bits - 1)
    remainder = 0
    for i in xrange(bits - 1):
        remainder = (remainder << 1) + 1

    if value & highest_bit_mask == highest_bit_mask:
        value = (value & remainder) - highest_bit_mask
    else:
        value = value & remainder
    return value
Vasu
  • 1,090
  • 3
  • 18
  • 35

1 Answers1

19

The following code delivers the same results as your function, but is a bit shorter. Also, obviously, if you are going to apply this to a lot of data, you can pre-calculate both the masks.

def sign_extend(value, bits):
    sign_bit = 1 << (bits - 1)
    return (value & (sign_bit - 1)) - (value & sign_bit)
Patrick Maupin
  • 8,024
  • 2
  • 23
  • 42
  • very clever indeed – Sven Sep 06 '21 at 16:14
  • Is their a small example on how to use it ? sign_extend(0xFF, 32) produces 255 which is same as 0xFF. I expect it to be 0xFFFFFFFF instead – nurabha May 11 '22 at 07:16
  • sign_extend(10,4) produces -6 which is signed equivalent (2's complement) value of unsigned value 10 when represented with 4 bits. sign_extend(10,5) produces value 10 or '0b1010'. I expected it would produce '0b11010' instead or value 26. This doesn't appear sign extension operation to me but rather signed representation of a value in given number of bits – nurabha May 11 '22 at 07:44
  • The purpose of this function is to extend the sign bit of a fixed width integer into a Python int, not to do negation. The apparent negation you are seeing with sign_extend(10, 4) is because 10 cannot actually be represented in a 4 bit two's-complement value. But 10 can be represented in a 5 bit two's complement value, and it's sign bit is -- wait for it -- zero. Which is extended properly by the function. Now if you put in 26, 5, then, yeah, you'll see a negative number come out. – Patrick Maupin May 12 '22 at 13:59
  • @nurabha You should call it this way: sign_extend(0xFF, 8). The bits argument is the number of bits in the input; the output is always the size of a Python signed integer. – Brian A. Henning Aug 12 '22 at 14:09