Z3py: Array of specific integer type? - python

In Z3Python, I want to declare an array of bytes (meaning each member of array is of integer of 8 bits). I tried with the following code, but apparently it reports that Int(8) is illegal type.
Any idea on how to fix the problem? Thanks!
I = IntSort()
I8 = Int(8)
A = Array('A', I, I8)

You cannot provide a number as argument of the Int() function. It expects a string (the name of the integer actually) and not the size, in bits, of the integer. You might want to consider using bit vectors instead:
Byte = BitVecSort(8)
i8 = BitVec('i8', Byte)
A = Array('A', IntSort(), Byte)

Related

Python - Integer to bytes object smallest possible size

I'm in a special circumstance where I would like to convert an integer into a bytes object of the smallest length possible. I currently use the following method to covert to bytes:
number = 9847
bytes = number.to_bytes(4, 'little')
However I would like to scale that the amount of bytes used down (the 4) to the smallest possible size. How can I achieve this?
I figured it out on my own! I use the following function to do the conversion to bytes for me now:
import math
def int_to_bytes(self, integer_in: int) -> bytes:
"""Convert an integer to bytes"""
# Calculates the least amount of bytes the integer can be fit into
length = math.ceil(math.log(integer_in)/math.log(256))
return integer_in.to_bytes(length, 'little')
This works because with exponents a = b^e is equivalent to e = log(a)/log(b)
In this case our problem is integer_in = 256^e, and we want to solve for e. This can be solved by rephrasing it to e = log(integer_in)/log(256). Lastly, we use math.ceil() to round up the answer to an integer.

Byte array in Python only accepts unsigned integers

I'm working on audio codecs in Python (yikes) using byte arrays to edit individual byte data from an audio file.
I have a certain encryption in mind that requires me to perform bit wise operations on single bytes stored in the byte-array.
One of those operations is the ~ operator (bitwise NOT) which essentially reverses the bit (b'0001 becomes b'1110).
The problem is when you reference a single element of a byte array, it returns an int (does Python by default consider untyped 8 bit data integers?). Integers in Python are by default signed (I don't think unsigned integers even exist in Python).
When you try to perform bit-wise NOT on a byte in the byte-array, you get the following error:
>>> array[0] = ~array[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: byte must be in range(0, 256)
This is because it expects an unsigned int between 0-255. How do I convert a signed int into an unsigned int such that the bits used to represent both values remain the same?
Cheers
Use a different operation for bit flipping.
E.g.:1
array[i] = 255 - array[i]
or also:
array[i] = 255 ^ array[i]
will flip all (i.e.: 8) bits.
1 the math behind this can be worked out from two's complement wikipedia page.
The solution is actually remarkably simple after playing around with a binary calculator a little bit.
Just subtract the magnitude of the SIGNED int from 256, to get the value of the UNSIGNED int with the same binary representation.
So,
-23 signed would be 233 unsigned.
Hope this helps anyone else looking for a solution :)
EDIT: For those saying answer is 255 - array[0]. In this case I'm looking for a way to go from post NOT'd int to its unsigned counter part. So I've already performed the bitwise NOT on the integer, now I'm just getting it back to a form that can be inputted into the byte-array.
So in the end it would look something like this:
tmp = ~array[0]
array[0] = 256 + tmp
or
array[0] = 256 - abs(tmp)
This gets me the correct answer :)

STL binary file reader with Python

I'm trying to write my "personal" python version of STL binary file reader, according to WIKIPEDIA : A binary STL file contains :
an 80-character (byte) headern which is generally ignored.
a 4-byte unsigned integer indicating the number of triangular facets in the file.
Each triangle is described by twelve 32-bit floating-point numbers: three for the normal and then three for the X/Y/Z coordinate of each vertex – just as with the ASCII version of STL. After these follows a 2-byte ("short") unsigned integer that is the "attribute byte count" – in the standard format, this should be zero because most software does not understand anything else. --Floating-point numbers are represented as IEEE floating-point numbers and are assumed to be little-endian--
Here is my code :
#! /usr/bin/env python3
with open("stlbinaryfile.stl","rb") as fichier :
head=fichier.read(80)
nbtriangles=fichier.read(4)
print(nbtriangles)
The output is :
b'\x90\x08\x00\x00'
It represents an unsigned integer, I need to convert it without using any package (struct,stl...). Are there any (basic) rules to do it ?, I don't know what does \x mean ? How does \x90 represent one byte ?
most of the answers in google mention "C structs", but I don't know nothing about C.
Thank you for your time.
Since you're using Python 3, you can use int.from_bytes. I'm guessing the value is stored little-endian, so you'd just do:
nbtriangles = int.from_bytes(fichier.read(4), 'little')
Change the second argument to 'big' if it's supposed to be big-endian.
Mind you, the normal way to parse a fixed width type is the struct module, but apparently you've ruled that out.
For the confusion over the repr, bytes objects will display ASCII printable characters (e.g. a) or standard ASCII escapes (e.g. \t) if the byte value corresponds to one of them. If it doesn't, it uses \x##, where ## is the hexadecimal representation of the byte value, so \x90 represents the byte with value 0x90, or 144. You need to combine the byte values at offsets to reconstruct the int, but int.from_bytes does this for you faster than any hand-rolled solution could.
Update: Since apparent int.from_bytes isn't "basic" enough, a couple more complex, but only using top-level built-ins (not alternate constructors) solutions. For little-endian, you can do this:
def int_from_bytes(inbytes):
res = 0
for i, b in enumerate(inbytes):
res |= b << (i * 8) # Adjust each byte individually by 8 times position
return res
You can use the same solution for big-endian by adding reversed to the loop, making it enumerate(reversed(inbytes)), or you can use this alternative solution that handles the offset adjustment a different way:
def int_from_bytes(inbytes):
res = 0
for b in inbytes:
res <<= 8 # Adjust bytes seen so far to make room for new byte
res |= b # Mask in new byte
return res
Again, this big-endian solution can trivially work for little-endian by looping over reversed(inbytes) instead of inbytes. In both cases inbytes[::-1] is an alternative to reversed(inbytes) (the former makes a new bytes in reversed order and iterates that, the latter iterates the existing bytes object in reverse, but unless it's a huge bytes object, enough to strain RAM if you copy it, the difference is pretty minimal).
The typical way to interpret an integer is to use struct.unpack, like so:
import struct
with open("stlbinaryfile.stl","rb") as fichier :
head=fichier.read(80)
nbtriangles=fichier.read(4)
print(nbtriangles)
nbtriangles=struct.unpack("<I", nbtriangles)
print(nbtriangles)
If you are allergic to import struct, then you can also compute it by hand:
def unsigned_int(s):
result = 0
for ch in s[::-1]:
result *= 256
result += ch
return result
...
nbtriangles = unsigned_int(nbtriangles)
As to what you are seeing when you print b'\x90\x08\x00\x00'. You are printing a bytes object, which is an array of integers in the range [0-255]. The first integer has the value 144 (decimal) or 90 (hexadecimal). When printing a bytes object, that value is represented by the string \x90. The 2nd has the value eight, represented by \x08. The 3rd and final integers are both zero. They are presented by \x00.
If you would like to see a more familiar representation of the integers, try:
print(list(nbtriangles))
[144, 8, 0, 0]
To compute the 32-bit integers represented by these four 8-bit integers, you can use this formula:
total = byte0 + (byte1*256) + (byte2*256*256) + (byte3*256*256*256)
Or, in hex:
total = byte0 + (byte1*0x100) + (byte2*0x10000) + (byte3*0x1000000)
Which results in:
0x00000890
Perhaps you can see the similarities to decimal, where the string "1234" represents the number:
4 + 3*10 + 2*100 + 1*1000

Why does a Python bytearray work with value >= 256

The Python documentation for bytearray states:
The bytearray type is a mutable sequence of integers in the range 0 <=
x < 256.
However the following code suggests values can be >= 256. I store a 9 bit binary number which has a maximum value of: 2^9-1 = 512-1 = 511
ba = bytes([0b111111111])
print '%s' % (ba)
The 9 bit binary number is printed as decimal 511:
[511]
I don't know what the intended behavior is, but I assumed the most significant bit(s) would be dropped to give an 8 bit number.
You aren't actually creating a bytearray or a bytes object, you're just creating a string containing '[511]', since bytes in Python 2 is just a synonym for str. In Python 3, you would get an error message:
ValueError: byte must be in range(0, 256)
The following code works in Python 2 or Python 3; note that I'm passing an 8 bit number, so it's in range.
ba = bytearray([0b11111111])
print(repr(ba))
output
bytearray(b'\xff')
code:
a = 511
byte = a.to_bytes(byte length goes here, 'little')
to decode:
a = int.from_bytes(byte, 'little')

Convert a list of ints to a float

I am trying to convert a number stored as a list of ints to a float type. I got the number via a serial console and want to reassemble it back together into a float.
The way I would do it in C is something like this:
bit_data = ((int16_t)byte_array[0] << 8) | byte_array[1];
result = (float)bit_data;
What I tried to use in python is a much more simple conversion:
result = int_list[0]*256.0 + int_list[1]
However, this does not preserve the sign of the result, as the C code does.
What is the right way to do this in python?
UPDATE:
Python version is 2.7.3.
My byte array has a length of 2.
in the python code byte_array is list of ints. I've renamed it to avoid misunderstanding. I can not just use the float() function because it will not preserve the sign of the number.
I'm a bit confused by what data you have, and how it is represented in Python. As I understand it, you have received two unsigned bytes over a serial connection, which are now represented by a list of two python ints. This data represents a big endian 16-bit signed integer, which you want to extract and turn into a float. eg. [0xFF, 0xFE] -> -2 -> -2.0
import array, struct
two_unsigned_bytes = [255, 254] # represented by ints
byte_array = array.array("B", two_unsigned_bytes)
# change above to "b" if the ints represent signed bytes ie. in range -128 to 127
signed_16_bit_int, = struct.unpack(">h", byte_array)
float_result = float(signed_16_bit_int)
I think what you want is the struct module.
Here's a round trip snippet:
import struct
sampleValue = 42.13
somebytes = struct.pack('=f', sampleValue)
print(somebytes)
result = struct.unpack('=f', somebytes)
print(result)
result may be surprising to you. unpack returns a tuple. So to get to the value you can do
result[0]
or modify the result setting line to be
result = struct.unpack('=f', some bytes)[0]
I personally hate that, so use the following instead
result , = struct.unpack('=f', some bytes) # tuple unpacking on assignment
The second thing you'll notice is that the value has extra digits of noise. That's because python's native floating point representation is double.
(This is python3 btw, adjust for using old versions of python as appropriate)
I am not sure I really understand what you are doing, but I think you got 4 bytes from a stream and know them to represent a float32 value. The way you handling this suggests big-endian byte-order.
Python has the struct package (https://docs.python.org/2/library/struct.html) to handle bytestreams.
import struct
stream = struct.pack(">f", 2/3.)
len(stream) # 4
reconstructed_float = struct.unpack(">f", stream)
Okay, so I think int_list isn't really just a list of ints. The ints are constrained to 0-255 and represent bytes that can be built into a signed integer. You then want to turn that into a float. The trick is to set the sign of the first byte properly and then procede much like you did.
float((-(byte_array[0]-127) if byte_array[0]>127 else byte_array[0])*256 + byte_array[1])

Categories

Resources