简体   繁体   中英

Unsigned ints of arbitrary length in python

I am trying to simulate a fixed-point filter implementation. I want to capture low-level hardware features like 2s-complement wraparound/overflow and fixed register widths. Some of the registers widths are set by hardware features at unusual and long widths (ie 72b).

I've been making some progress using the built-in integers. The infinite width is incredibly useful... but I find myself fighting Python a lot because it sometimes wants to interpret a binary as a positive integer, and sometimes it seems to want to interpret a very similar binary as a negative 2's complement. For example:

>> a = 0b11111                          # sign-extended -1
>> b = 0b0011
>> print("{0:b}".format(a*b))
5f
>> print("{0:b}".format((a*b)&a))       # Truncate to correct product length
11101                                   # == -3 in 2s complement. Great!
>> print("{0:b}".format(~((a*b)&a)+1))  # Actually perform the 2's complement
-11101                                  # Arrrrggggghhh
>> print("{0:b}".format((~((a*b)&a)&a)+1))  # Truncate with extreme prejudice
11                                          # OK. Fine.

I guess if I think hard enough I can figure out why all this works the way it does, but if I could just do it all in unsigned space without worrying about python adding sign bits it would make things easier and less error-prone. Anyone know if there's a relatively easy way to do this? I considered bit strings, but I have to do a lot of adds & multiplies in this application and built-in integer arithmetic is really useful for that.

~x is literally defined on arbitrary precision integers as -(x+1) . It does not do bit arithmetic: ~0 is 255 in one-byte integers, 65535 in two-byte integers, 1023 for 10-bit integers etc; so defining ~ via bit inversion on stretchy integers is useless.

If a defines the fixed width of your integers (with 0b11111 saying you are working with five-bit numbers), bit inversion is as simple as a^x .

print("{0:b}".format(a ^ b)
# => 11100

Two's complement is meanwhile easiest done as a+1-b , or equivalently a^b+1 :

print("{0:b}".format((a + 1) - b))
# => 11101
print("{0:b}".format((a ^ b) + 1))
# => 11101

tl;dr: Don't use ~ if you want to stay unsigned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM