Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert signed to unsigned integer in python

Let's say I have this number i = -6884376. How do I refer to it as to an unsigned variable? Something like (unsigned long)i in C.

like image 250
Lior Avatar asked Dec 24 '13 21:12

Lior


People also ask

How do you convert a signed integer to an unsigned integer in python?

Python doesn't have builtin unsigned types. you can use abs() function.

How do you convert a signed integer to an unsigned integer?

To convert a signed integer to an unsigned integer, or to convert an unsigned integer to a signed integer you need only use a cast. For example: int a = 6; unsigned int b; int c; b = (unsigned int)a; c = (int)b; Actually in many cases you can dispense with the cast.

Does Atoi work for unsigned int?

The longer answer is that even if all you needed was signed 32 bit integers or were happy with 31 bits for unsigned, the atoi() function is a poor fit for what you appear to be doing. As you have already noted, the atoi() function converts a string to an integer. A normal, signed integer.


Video Answer


2 Answers

Assuming:

  1. You have 2's-complement representations in mind; and,
  2. By (unsigned long) you mean unsigned 32-bit integer,

then you just need to add 2**32 (or 1 << 32) to the negative value.

For example, apply this to -1:

>>> -1 -1 >>> _ + 2**32 4294967295L >>> bin(_) '0b11111111111111111111111111111111' 

Assumption #1 means you want -1 to be viewed as a solid string of 1 bits, and assumption #2 means you want 32 of them.

Nobody but you can say what your hidden assumptions are, though. If, for example, you have 1's-complement representations in mind, then you need to apply the ~ prefix operator instead. Python integers work hard to give the illusion of using an infinitely wide 2's complement representation (like regular 2's complement, but with an infinite number of "sign bits").

And to duplicate what the platform C compiler does, you can use the ctypes module:

>>> import ctypes >>> ctypes.c_ulong(-1)  # stuff Python's -1 into a C unsigned long c_ulong(4294967295L) >>> _.value 4294967295L 

C's unsigned long happens to be 4 bytes on the box that ran this sample.

like image 72
Tim Peters Avatar answered Oct 03 '22 15:10

Tim Peters


To get the value equivalent to your C cast, just bitwise and with the appropriate mask. e.g. if unsigned long is 32 bit:

>>> i = -6884376 >>> i & 0xffffffff 4288082920 

or if it is 64 bit:

>>> i & 0xffffffffffffffff 18446744073702667240 

Do be aware though that although that gives you the value you would have in C, it is still a signed value, so any subsequent calculations may give a negative result and you'll have to continue to apply the mask to simulate a 32 or 64 bit calculation.

This works because although Python looks like it stores all numbers as sign and magnitude, the bitwise operations are defined as working on two's complement values. C stores integers in twos complement but with a fixed number of bits. Python bitwise operators act on twos complement values but as though they had an infinite number of bits: for positive numbers they extend leftwards to infinity with zeros, but negative numbers extend left with ones. The & operator will change that leftward string of ones into zeros and leave you with just the bits that would have fit into the C value.

Displaying the values in hex may make this clearer (and I rewrote to string of f's as an expression to show we are interested in either 32 or 64 bits):

>>> hex(i) '-0x690c18' >>> hex (i & ((1 << 32) - 1)) '0xff96f3e8' >>> hex (i & ((1 << 64) - 1) '0xffffffffff96f3e8L' 

For a 32 bit value in C, positive numbers go up to 2147483647 (0x7fffffff), and negative numbers have the top bit set going from -1 (0xffffffff) down to -2147483648 (0x80000000). For values that fit entirely in the mask, we can reverse the process in Python by using a smaller mask to remove the sign bit and then subtracting the sign bit:

>>> u = i & ((1 << 32) - 1) >>> (u & ((1 << 31) - 1)) - (u & (1 << 31)) -6884376 

Or for the 64 bit version:

>>> u = 18446744073702667240 >>> (u & ((1 << 63) - 1)) - (u & (1 << 63)) -6884376 

This inverse process will leave the value unchanged if the sign bit is 0, but obviously it isn't a true inverse because if you started with a value that wouldn't fit within the mask size then those bits are gone.

like image 41
Duncan Avatar answered Oct 03 '22 13:10

Duncan