Signed decimal from a signed hex short in python - python

I was wondering if theres any easy and fast way to obtain the decimal value of a signed hex in python.
What I do to check the value of a hex code is just open up python in terminal and type in the hex, it returns the decimal like this:
>>>0x0024
36
>>>0xcafe
51966
So I was wondering, is there any way that I could do that for signed short hex? for example 0xfffc should return -4

import ctypes
def hex2dec(v):
return ctypes.c_int16(v).value
print hex2dec(0xfffc)
print hex2dec(0x0024)
print hex2dec(0xcafe)

You can use the int classmethod from_bytes and provide it with the bytes:
>>> int.from_bytes(b'\xfc\xff', signed=True, byteorder='little')
-4

If you can use NumPy numerical types you could use np.int16 type conversion
>>> import numpy as np
>>> np.int16(0x0024)
36
>>> np.int16(0xcafe)
-13570
>>> np.int16(0xfffc)
-4
>>> np.uint16(0xfffc)
65532
>>> np.uint16(0xcafe)
51966
Python Language specifies a unified representation for integer numbers, the numbers.Integral class, a subtype of numbers.Rational. In Python 3 there are no specific constraints on the range of this type. In Python 2 only the minimal range is specified, that is numbers.Integral should have at least the range of -2147483648 through 2147483647, that corresponds to the 32 bit representation.
NumPy implementation is closer to the machine architecture. To implement numeric operations efficiently it provides fixed width datatypes, such as int8, int16, int32, and int64.

Related

Python binary float to integer conversion using ctypes

Please help me to understand this code snippet:
def binary_float_to_int(float_number: float) -> int:
return ctypes.c_uint.from_buffer(ctypes.c_float(float_number)).value
The results from these inputs:
print(binary_float_to_int(7.1746481e-43))
print(binary_float_to_int(5.3809861e-43))
Are: 512 & 384
Why does the simple Python conversion int(7.1746481e-43) not work?
Are there any other ways to do this type of conversion?
The ctypes code is:
Put the floating point number in a 32-bit C (IEEE 754-format) ctypes.c_float(float_number)
Treat that same 4-byte value, as an C unsigned int. ctypes.c_uint.from_buffer()
Extract that unsigned integer value .value
Your numbers are correct, if you want the raw 32-bit value of those floating point numbers expressed as integers. Here's another way to do it:
>>> import struct
>>> struct.unpack('i',struct.pack('f',7.1746481e-43))[0]
512
>>> struct.unpack('i',struct.pack('f',5.3809861e-43))[0]
384
These generate the 4-byte float32 value, then unpack it as an integer.
7.1746481e-43 is a very small value close to zero. int() returns the integer portion...in this case, zero, so that's as expected as well.

How to accurately interpret large float numbers in Python

I want to calculate additions of a very large number (type, float) and a very small number using Python 2.7.
For example:
>> x = 1546439400046560970.
>> y = 1.
>> print(int(x + y))
1546439400046561024
This is not right. Correct answer is 1546439400046560971.
I realize that the problem is due to type cast from float to int. How could I solve this problem, if I want to get the correct answer?
I realize that the problem is due to type cast from float to int.
Not really. The float itself does not store your value precisely. You can prove that this is the case by converting to a type that has more precision than a float, for example decimal.
>>> import decimal
>>> decimal.decimal(1546439400046560971.)
Decimal('1546439400046561024')
So any solution that initially stores x as a float is doomed to fail, even if you never use the int type.
One possible solution is to store your values as decimals to begin with. Remember to initialize them using strings and not floats, or else the precision will be lost.
>>> from decimal import Decimal
>>> x = Decimal("1546439400046560971")
>>> y = Decimal("1")
>>> x+y
Decimal('1546439400046560972')

Copying internal formats float64 uint64

I'm using Numpy and Python. I need to copy data, WITHOUT numeric conversion between np.uint64 and np.float64, e.g. 1.5 <-> 0x3ff8000000000000.
I'm aware of float.hex, but the output format a long way from uint64:
In [30]: a=1.5
In [31]: float.hex(a)
Out[31]: '0x1.8000000000000p+0'
Im also aware of various string input routines for the other way.
Can anybody suggest more direct methods? After all, its just simple copy and type change but python/numpy seem really rigid about converting the data on the way.
Use an intermediate array and the frombuffer method to "cast" one array type into the other:
>>> v = 1.5
>>> fa = np.array([v], dtype='float64')
>>> ua = np.frombuffer(fa, dtype='uint64')
>>> ua[0]
4609434218613702656 # 0x3ff8000000000000
Since frombuffer creates a view into the original buffer, this is efficient even for reinterpreting data in large arrays.
So, what you need is to see the 8 bytes that represent the float64 in memory as an integer number. (representing this int64 number as an hexadecimal string is another thing - it
is just its representation).
The Struct and Union functionality that comes bundled with the stdlib's ctypes
may be nice for you - no need for numpy. It has a Union type that works
quite like C language unions, and allow you to do this:
>>> import ctypes
>>> class Conv(ctypes.Union):
... _fields_ = [ ("float", ctypes.c_double), ("int", ctypes.c_uint64)]
...
>>> c = Conv()
>>> c.float = 1.5
>>> print hex(c.int)
0x3ff8000000000000L
The built-in "hex" function is a way to get the hexadecimal representation of the number.
You can use the struct module as well: pack the number to a string as a double, and unpack it as int. I think it is both less readable and less efficient than using ctypes Union:
>>> inport struct
>>> hex(struct.unpack("<Q", struct.pack("<d", 1.5))[0])
'0x3ff8000000000000'
Since you are using numpy , however, you can simply change the array type, "on the fly", and manipulate all the array as integers with 0 copy:
>>> import numpy
>>> x = numpy.array((1.5,), dtype=numpy.double)
>>> x[0]
1.5
>>> x.dtype=numpy.dtype("uint64")
>>> x[0]
4609434218613702656
>>> hex(x[0])
'0x3ff8000000000000L'
This is by far the most efficient way of doing it, whatever is your purpose in getting the raw bytes of the float64 numbers.

python standard library - int

I was reading through the documentation to the Python Standard Library. In section 4.4. Numeric Types there is a note to int:
Conversion from floating point to integer may round or truncate as in
C
What does this mean? I thought int always returned the floor? Is that not the case?
>>> print(int(0.4))
0
>>> print(int(0.6))
0
Conversion from a float to a integer truncates towards 0 as it does in C. This is basically equivalent to math.floor(abs(x))*sgn(x), where sgn(x) gives the sign of a number.

complex-valued math evaluations permitted in Python but not in numpy

Is this documented anywhere? Why such a drastic difference?
# Python 3.2
# numpy 1.6.2 using Intel's Math Kernel Library
>>> import numpy as np
>>> x = np.float64(-0.2)
>>> x ** 0.8
__main__:1: RuntimeWarning: invalid value encountered in double_scalars
nan
>>> x = -0.2 # note: `np.float` is same built-in `float`
>>> x ** 0.8
(-0.2232449487530631+0.16219694943147778j)
This is especially confusing since according to this, np.float64 and built-in float are identical except for __repr__.
I can see how the warning from np may be useful in some cases (especially since it can be disabled or enabled in np.seterr); but the problem is that the return value is nan rather than the complex value provided by the built-in. Therefore, this breaks code when you start using numpy for some of the calculations, and don't convert its return values to built-in float explicitly.
numpy.float may or may not be float, but complex numbers are not float at all:
In [1]: type((-0.2)**0.8)
Out[1]: builtins.complex
So there's no float result of the operation, hence nan.
If you don't want to do an explicit conversion to float (which is recommended), do the numpy calculation in complex numbers:
In [3]: np.complex(-0.2)**0.8
Out[3]: (-0.2232449487530631+0.16219694943147778j)
The behaviour of returning a complex number from a float operation is certainly not usual, and was only introduced with Python 3 (like the float division of integers with the / operator). In Python 2.7 you get the following:
In [1]: (-0.2)**0.8
ValueError: negative number cannot be raised to a fractional power
On a scalar, if instead of np.float64 you use np.float, you'll get the same float type as Python uses. (And you'll either get the above error in 2.7 or the complex number in 3.x.)
For arrays, all the numpy operators return the same type of array, and most ufuncs do not support casting from float > complex (e.g., check np.<ufunc>.type).
If what you want is a consistent operation on scalars, use np.float
If you are interested in array operations, you'll have to cast the array as complex: x = x.astype('complex')

Categories