Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:48:48

0001 #!/usr/bin/env python
0002 """
0003 intpack.py
0004 ------------
0005 
0006 Thinking about twos-complement representation of signed integers 
0007 and bit packing. See SSys::unsigned_as_int 
0008 
0009 When packing signed ints have to be more careful with the masking
0010 to avoid getting "leaking" bits as -1:0xffffffff 
0011 
0012 ::
0013 
0014     In [15]: ( 0 << 16 )    
0015     Out[15]: 0
0016     In [16]: ( 0 << 16 ) | -1
0017     Out[16]: -1
0018     In [17]: pack = ( 0 << 16 ) | -1
0019     In [18]: pack >> 16
0020     Out[18]: -1
0021     In [19]: pack = ( ( 0 & 0xffff)  << 16 ) | ( -1 & 0xffff )
0022     In [20]: "%x" % pack
0023     Out[20]: 'ffff'
0024     In [21]: pack >> 16
0025     Out[21]: 0
0026 
0027 """
0028 import sys, binascii as ba, numpy as np
0029 x_ = lambda _:ba.hexlify(_)
0030 
0031 num_bytes = 4
0032 signed_max = (0x1 << (num_bytes*8 - 1)) - 1 
0033 
0034 ii = list(range(-10,10)) + list(range(signed_max - 10, signed_max+1)) + list(range(-(signed_max+1), -signed_max+10))
0035 
0036 assert sys.byteorder == 'little'
0037 
0038 
0039 i2big_ = lambda _:ba.hexlify(_.to_bytes(2, "big", signed=True )).decode()   
0040 i4big_ = lambda _:ba.hexlify(_.to_bytes(4, "big", signed=True )).decode()   
0041 
0042 
0043 
0044 
0045 for i in ii:
0046    u = np.uint32(i)
0047    v = u.view(np.int32)
0048    assert v == i 
0049 
0050    uhi = ( u & 0xffff0000 ) >> 16 
0051    ulo = ( u & 0x0000ffff ) >> 0
0052 
0053    l = i.to_bytes(num_bytes, "little", signed=True )  
0054    b = i.to_bytes(num_bytes, "big", signed=True )  
0055 
0056    print("i:%12d u:%12d x:%8x xhi:%4x xlo:%4x        little:%10s  big:%10s " % (i,u,u,uhi,ulo,x_(l), x_(b)))
0057 pass
0058 
0059 print("(endianness is implementation detail that only very rarely need to think about even when masking and packing, only relevant when doing very low level debug eg with xxd)")
0060 print("(splitting a 16 bit value across two adjacent 8 bit fields and then reinterpreting them as 16 bit is one example where would need to consider endianness)") 
0061 print("little: least significant byte is first in memory")
0062 print("   big: least significant byte is last in memory")
0063 print("     x: hex string presentation looks like big-endian, the less common endianness" )
0064 print(" sys.byteorder : %s " % sys.byteorder)  
0065 
0066 
0067 
0068 # packing signed ints in unsigned array 
0069 
0070 n0 = np.arange(0, -100, -1, dtype=np.int32)  
0071 n1 = -1000 + n0 
0072 
0073 nn = np.zeros(len(n0), dtype=np.uint32)
0074 
0075 nn[:] = (( n0 & 0xffff ) << 16 ) | ((n1 & 0xffff) << 0 )
0076  
0077 ## with negative ints have to downsize the container and pluck the evens
0078 ## because of twos-complement rep of signed integers
0079 n0chk = ( n0 & 0xffff ).view(np.int16)[::2]    
0080 assert np.all( n0chk == n0 )
0081 
0082 n1chk = ( n1 & 0xffff ).view(np.int16)[::2] 
0083 assert np.all( n1chk == n1 )
0084 
0085 nn_0 = (nn >> 16).view(np.int16)[::2] 
0086 assert np.all( n0 == nn_0 ) 
0087 
0088 nn_1 = (nn & 0xffff).view(np.int16)[::2] 
0089 assert np.all( n1 == nn_1 ) 
0090 
0091 
0092 # compare with packing unsigned ints in unsigned array
0093 p0 = np.arange(0, 100, dtype=np.uint32)
0094 p1 = 1000 + p0 
0095 pp = np.zeros( len(p0), dtype=np.uint32) 
0096 
0097 pp[:] = (( p0 & 0xffff ) << 16 ) | ((p1 & 0xffff) << 0 )
0098 
0099 p0chk = p0 & 0xffff   
0100 assert np.all( p0chk == p0 )
0101 
0102 p0chk_ = ( p0 & 0xffff ).view(np.int16)[::2]  ## works, but not needed for +ve 
0103 assert np.all( p0chk_ == p0 )
0104 
0105 p1chk = p1 & 0xffff   
0106 assert np.all( p1chk == p1 )
0107 
0108 p1chk_ = ( p1 & 0xffff ).view(np.int16)[::2]   ## works, but not needed for +ve 
0109 assert np.all( p1chk_ == p1 )
0110 
0111 
0112 # cover the whole 16 bit range and one extra that clocks it at each end
0113 r0 = np.arange(-0x7fff-1-1, 0x7fff+1+1, dtype=np.int32) 
0114 r1 = r0[::-1]
0115 
0116 rr = np.zeros( len(r0), dtype=np.uint32 )
0117 rr[:] = ((r0 & 0xffff) << 16 ) | ((r1 & 0xffff) << 0)
0118 
0119 rr_0 = (rr >> 16).view(np.int16)[::2] 
0120 rr_1 = (rr & 0xffff).view(np.int16)[::2] 
0121 
0122 # just the one steps beyond dont match 
0123 assert len(np.where( rr_0 != r0 )[0]) == 2  
0124 assert len(np.where( rr_1 != r1 )[0]) == 2  
0125 
0126 
0127 
0128