Bit length of int or long?
Darrell Gallion
darrell at dorb.com
Sun May 21 20:50:40 EDT 2000
"Carey Evans"
> I found when rewriting crypt() in Python that nearly all the right
> shifts were by constants, so I could write something like
>
> ((t >> 18) & 0x3fff)
>
> to trim off the sign bits.
Yeah, but...
>>> x=0xffffffff
>>> x
-1
>>> hex((x>>18)&0x3fffffff)
'0x3fffffff'
>>> hex((x>>2)&0x3fffffff)
'0x3fffffff'
>>> hex((x>>5)&0x3fffffff)
'0x3fffffff'
>>>
You inspired me to write :)
import sys, string, re
class BitMath:
def __init__(self, negOne=-1):
self._maskCache={}
self._negOne=negOne # Just in case word sizes want to change.
self._wordSize=self.bitLen(negOne)
self._signBitMask= 1 << (self._wordSize-1)
self._signBitMaskRightOne= 1 << (self._wordSize-2)
def test(self):
pat=re.compile("test.")
dic=self.__class__.__dict__
for n in dic.keys():
if pat.match(n):
dic[n](self)
def getMask(self, sz):
"""
Return a mask of binary ones of len sz
"""
if self._maskCache.has_key(sz):
return self._maskCache[sz]
rm = sz%4
dic={0:'', 1:'1', 2:'3', 3:'7'}
res=['0x',dic[rm]]
for x in range(sz/4):
res.append('f')
val=eval(string.join(res,''))
self._maskCache[sz]=val
return val
def testGetMask(self):
for c in range(33):
val=self.getMask(c)
assert(val==self.shift(-1,-(32-c)))
def bitLen(self, x, wordLen=32):
"""
From Guido's post.
Fixed to handle unsigned numbers
Doesn't work with negative longs
>>> hex(0xfL ^ 0x80000000)
'-0x7FFFFFF1L'
>>> hex(0xf ^ 0x80000000)
'0x8000000f'
"""
global signBitMask
n = 0
if x > 0:
while x:
n = n+1
x = x>>1
elif x == -1:
assert(type(x) != type(1L))
n= wordLen
else:
assert(type(x) != type(1L))
n= self.bitLen(x ^ self._signBitMask)+1
return n
def testBitLen(self):
assert(self.bitLen(-1)==32)
assert(self.bitLen(0xf)==4)
assert(self.bitLen(999999999999999L)==50)
def shift(self, x, cnt):
"""
shift right if cnt > 0
shift left if cnt < 0
Right shift fills with zeros
"""
if cnt==0:
return x
y=x
if x > 0 or cnt > 0:
if cnt < 0:
y = x >> -cnt
elif cnt > 0:
y = x << cnt
else:
x = x ^ self._signBitMask
y = x >> 1
y = y | self._signBitMaskRightOne
y = y >> (-cnt-1)
return y
def testShift(self):
assert(self.shift(-1, -2) == 0x3fffffff)
assert(self.shift(-1, -32) == 0)
assert(self.shift(0xf, 4) == 0xf0)
assert(self.shift(0xa5000000, -8) == 0xa50000)
def showShift(self):
"""
Demo shift
"""
def show(start, func):
for c in range(10):
res=func(start, c)
print "%-4d%08x%15d"%(c, res, res)
print "*"*50
show(-1, self.shift)
show(sys.maxint, self.shift)
def rotate(self, x, cnt):
"""
rotate bits by cnt
Bits are recirculated to the opposite end
"""
if cnt==0:
return x
bitLx = self.bitLen(x)
cnt1= (cnt % self._wordSize)
temp1= self.shift(x, -(self._wordSize - cnt1))
temp2= self.shift(x, cnt1)
return temp2 | temp1
def testRotate(self):
last=1
for c in range(10):
if 0:
print "%08x"%self.rotate(0xa5000000,-c*4)
print "%08x"%self.rotate(0xa5000000,c*4)
print '-----------'
temp=self.rotate(1,c*4)
if temp > last:
assert(temp == last * 16)
else:
assert(temp==1)
last=temp
bitMath=BitMath()
bitMath.test()
bitMath.showShift()
More information about the Python-list
mailing list