Converting hexadecimal value to decimal in Python - python

I just started working with hexadecimal values in python and am a bit surprised with what I just encountered. I expected the following code to first print a hexadecimal string, and then a decimal value.
Input:
n = 0x8F033CAE74F88BA10D2BEA35FFB0EDD3
print('Hex value for n is:', n)
print('Dec value for n is:', int(str(n), 16))
Output:
Hex value for n is: 190096411054295805012706659640261275091
Dec value for n is: 8921116140846515089057635273465667902228615313
How is it possible that 2 different different numbers are shown? I expected the first number to be a hexadecimal string and the second it's decimal equivalent, what is this second value in this case?

0x is a way to input an integer with an hexadecimal notation.
>>> n = 0x8F033CAE74F88BA10D2BEA35FFB0EDD3
This hexadecimal notation is forgotten directly after instantiation, though:
>>> n
190096411054295805012706659640261275091
>>> str(n)
'190096411054295805012706659640261275091'
So when you call int(str(n), 16), Python interprets '190096411054295805012706659640261275091' as an hexadecimal number:
>>> int(str(n), 16)
8921116140846515089057635273465667902228615313
You need to input the original hex string:
>>> int("8F033CAE74F88BA10D2BEA35FFB0EDD3", 16)
190096411054295805012706659640261275091
or use hex:
>>> int(hex(n), 16)
190096411054295805012706659640261275091

Related

How to convert a char to signed integer in python

I don't have much experience with Python, so I need your help!
In the following example I can convert a char to unsigned integer, but i need a signed integer. How can I convert a char to signed integer in python?
d="bd"
d=int(d,16)
print (d)
The Result is: 189
but I expect: -67
First a nitpick: It's not a char, it's a string.
The main problem is that int() cannot know how long the input is supposed to be; or in other words: it cannot know which bit is the MSB (most significant bit) designating the sign. In python, int just means "an integer, i.e. any whole number". There is no defined bit size of numbers, unlike in C.
For int(), the inputs 000000bd and bd therefore are the same; and the sign is determined by the presence or absence of a - prefix.
For arbitrary bit count of your input numbers (not only the standard 8, 16, 32, ...), you will need to do the two-complement conversion step manually, and tell it the supposed input size. (In C, you would do that implicitely by assigning the conversion result to an integer variable of the target bit size).
def hex_to_signed_number(s, width_in_bits):
n = int(s, 16) & (pow(2, width_in_bits) - 1)
if( n >= pow(2, width_in_bits-1) ):
n -= pow(2, width_in_bits)
return n
Some testcases for that function:
In [6]: hex_to_signed_number("bd", 8)
Out[6]: -67
In [7]: hex_to_signed_number("bd", 16)
Out[7]: 189
In [8]: hex_to_signed_number("80bd", 16)
Out[8]: -32579
In [9]: hex_to_signed_number("7fff", 16)
Out[9]: 32767
In [10]: hex_to_signed_number("8000", 16)
Out[10]: -32768
print(int.from_bytes(bytes.fromhex("bd"), byteorder="big", signed=True))
You can convert the string into Bytes and then convert bytes to int by adding signed to True which will give you negative integer value.

Turning a fixed width hex string encoding a fixed width signed integer into the integer in Python

I have a 5 digit (20 bit) hex string that encodes a signed integer in twos complement. Is there a compact, simple way to extract the integer in Python?
n = int(s, 16) # get the unsigned value of your hex string
if n >= 2**19: # if sign bit is set...
n -= 2**20 # ...make it negative

Preventing auto scientific form for numbers in python3

Is it possible to not assign a scientific/standard form number when doing calculations?
for example right now in one of the lines in my code has:
number = 10**23 * 1.1
which is supposed to evaluate to 110000000000......0 or whatever, instead im assigned 1.1e+23 which is very annoying because im trying to convert IEEE754 to decimal and making specific things print out but it wont work because of the scientific notation of 1.1e+23
Ive tried looking around but no simple concise answers
You cannot change this by default. The default behavior when displaying a float is always to move to scientific notation if the exponent is larger than the float’s precision.
The only way to change this is by explicitly formatting it in another way. If you know what precision your displayed number should have, you can use format:
>>> number
1.1e+23
>>> format(number, 'f')
'110000000000000004194304.000000'
>>> format(number, '.0f')
'110000000000000004194304'
You can also use that with format strings:
>>> 'The number is {:.0f}'.format(number)
'The number is 110000000000000004194304'
If your goal is to conver the float into an integer, then you should just do that. Integers have infinite precision, so they are not displayed using scientific notation. You could for example round or cut off the digits after the decimal point:
>>> round(number)
110000000000000004194304
>>> int(number)
110000000000000004194304
For high-precision decimals, you can use the Decimal type. It allows for decimals to have an arbitrary precision:
>>> from decimal import Decimal
>>> d = 10**23 * Decimal('1.1')
>>> d
Decimal('110000000000000000000000.0')
>>> int(d)
110000000000000000000000
def number(n):
"""
如果小于1,只保留4位有效数字
如果大于1,保留小数点后2位
"""
if n < 1:
n = '{:.4g}'.format(n)
else:
n = '{:.2f}'.format(n)
if 'e-' in n:
a, b = n.split('e-')
a = a.replace('.', '')
b = int(b)
return '0.' + '0' * (b - 1) + a
else:
return n
In the above example, if it's less than 1, I keep 4 significant digits, if it's larger than 1, I keep all digits before the decimal point, and keep 2 digits after the decimal point. It's perfect for displaying price of cryptos ;)
In [61]: number(0.00000123456)
Out[61]: '0.000001235'
In [62]: number(47740.3413)
Out[62]: '47740.34'

two's complement of numbers in python

I am writing code that will have negative and positive numbers all 16 bits long with the MSB being the sign aka two's complement. This means the smallest number I can have is -32768 which is 1000 0000 0000 0000 in two's complement form. The largest number I can have is 32767 which is 0111 1111 1111 1111.
The issue I am having is python is representing the negative numbers with the same binary notation as positive numbers just putting a minus sign out the front i.e. -16384 is displayed as -0100 0000 0000 0000 what I want to be displayed for a number like -16384 is 1100 0000 0000 0000.
I am not quite sure how this can be coded. This is the code i have. Essentially if the number is between 180 and 359 its going to be negative. I need to display this as a twos compliment value. I dont have any code on how to display it because i really have no idea how to do it.
def calculatebearingActive(i):
numTracks = trackQty_Active
bearing = (((i)*360.0)/numTracks)
if 0< bearing <=179:
FC = (bearing/360.0)
FC_scaled = FC/(2**(-16))
return int(FC_scaled)
elif 180<= bearing <=359:
FC = -1*(360-bearing)/(360.0)
FC_scaled = FC/(2**(-16))
return int(FC_scaled)
elif bearing ==360:
FC = 0
return FC
If you're doing something like
format(num, '016b')
to convert your numbers to a two's complement string representation, you'll want to actually take the two's complement of a negative number before stringifying it:
format(num if num >= 0 else (1 << 16) + num, '016b')
or take it mod 65536:
format(num % (1 << 16), '016b')
The two's complement of a value is the one's complement plus one.
You can write your own conversion function based on that:
def to_binary(value):
result = ''
if value < 0:
result = '-'
value = ~value + 1
result += bin(value)
return result
The result looks like this:
>>> to_binary(10)
'0b1010'
>>> to_binary(-10)
'-0b1010'
Edit: To display the bits without the minus in front you can use this function:
def to_twoscomplement(bits, value):
if value < 0:
value = ( 1<<bits ) + value
formatstring = '{:0%ib}' % bits
return formatstring.format(value)
>>> to_twoscomplement(16, 3)
'0000000000000011'
>>> to_twoscomplement(16, -3)
'1111111111111101'
If you actually want to store the numbers using 16 bits, you can use struct.
import struct
>>> struct.pack('h', 32767)
'\xff\x7f'
>>> struct.pack('h', -32767)
'\x01\x80'
You can unpack using unpack
>>> a = struct.pack('h', 32767)
>>> struct.unpack('H', a)
32767
Python can hold unlimited integer values, the bit representation will adopt to hold any number you put. So such technical details as two complement does not make sense in this context. In C 'b1111111111111111' means -1 for int16 and 65535 for uint16 or int32. In python it is always is 65535 as the int will adopt to hold such values.
I think this is why they opted to add - in front of negative numbers regardless of string representation (binary, oct, hex, decimal ...).
If you wish to replicate the C behaviour and get the negative represented in two complement form you have the following options:
1 int > uint > bin using numpy
The most straight forward way is to dump the value as signed limited int and read it as unsigned.
If you have access to numpy the code is pretty easy to read:
>>> bin(np.int16(-30).astype(np.uint16))
'0b1111111111100010'
>>> bin(np.int16(-1).astype(np.uint16))
'0b1111111111111111'
>>> bin(np.int16(-2).astype(np.uint16))
'0b1111111111111110'
>>> bin(np.int16(-16).astype(np.uint16))
'0b1111111111110000'
2 int > uint > bin using struct
You can do the similar think with struct but it is slightly harder to understand
>>> bin(struct.unpack('>H', struct.pack('>h', 30))[0])
'0b1111111111100010'
>>> bin(struct.unpack('>H', struct.pack('>h', -1))[0])
'0b1111111111111111'
>>> bin(struct.unpack('>H', struct.pack('>h', -2))[0])
'0b1111111111111110'
>>> bin(struct.unpack('>H', struct.pack('>h', -16))[0])
'0b1111111111110000'
Note: h is signed and H is unsigned int 16, and '>' stands for bigendian it comes handy if you want to read bytes directly without converting them back to int
3. int using struct, then read byte by byte and convert to bin
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -1<<15))
'1000000000000000'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -1))
'1111111111111111'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -2))
'1111111111111110'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -16))
'1111111111110000'
Note this has some quirks, as you need to remember to enforce the byte binary representation to be 8 digits long with '08'.
3 Directly from math,
Lastly you can go check what wikipedia says about 2 complement representation and get it implemented directly from the math formula Two complement > Subtraction from 2N
>>> bin(2**16 -16)
'0b1111111111110000'
>>> bin(2**16 -3)
'0b1111111111111101'
This looks super simple but it is hard to understand if you are not versed in the way 2 complement representation works.
Since you haven't given any code examples, I can't be sure what's going on. Based on the numbers in your example, I don't think you're using bin(yourint) because you're output doesn't contain 0b. Maybe you're already slicing that off in your examples.
If you are storing your binary data as strings, you could do something like:
def handle_negatives(binary_string):
If binary_string < 0:
binary_string = '1' + str(binary_string)[1:]
Return binary_string
Here are some caveats in printing complements(1s and 2s) in binary form, in python:
UNSIGNED RANGE: 0 to (2^k)-1 for k bit number
ex: 0 to (2^32)-1 numbers
ex: 0 to 7 for 3 bit unsigned numbers (count = 8)
SIGNED RANGE: -2^(k-1) to +2^(k-1)-1 for 1+k bit number (k-1 is for dividing current range k into two equal half)
ex: -2^31 to +(2^31)-1 numbers
ex -8 to +7 for 1+3 bit signed numbers (count = 8)
bin(int)->str converts an integer to binary string
CAVEAT: 1. Since in python there is no limit to length of integer
for ~x or !x (1s_complement/not/negate) we can't determine how many bits after MSB needs to be 1
so python just prints out unsigned value of target negative number in binary format with a
'-' sign in the beginning
ex: for x = b'01010'(10) we get ~x = -0b'1011' (-11)
but we should be getting -16+5 = -11
(-b'10000'+b'00101') = -b'10101' (-11 signed) or (21 unsigned)
to get real binary value after negation(or 1s complement) one could simulate it
NOTE: 2^0 is always 1, so (2**0 == 1) in python
NOTE: (1 << k) is always 2^k (left shift is 2 raised to the power k)
ex: bin((1 << k)-1 - x) which is ((2^k)-1)-x (1s complement)
ex: bin((1 << k)-1 - x) + 1 which is (2^k)-x (2s complement)
2. Same goes for reverse parsing of signed binary string to int:
ex: int("-0b'0101'", 2) gives -5 but instead it actually is -11 assuming -0b represents all bits
from MSB till current to be like 1111......0101 which is actually -16+5 = -11
BUT due to PYTHON's limitation of representing signed binary values we need to adhere to
current way of parsing considering unsigned binary strings with sign in front for -ve numbers
# NOTE: how the significant prefix zeros doesn't matter in both +ve and -ve cases
# Byte type inputs
x = b'+1010' # valid +ve number byte string
x = b'1010' # valid +ve number byte string
x = b'-1010' # valid -ve number byte string
x = b'+01010' # valid +ve number byte string
x = b'01010' # valid +ve number byte string
x = b'-01010' # valid -ve number byte string
int(b'101') # interprets as base 10 for each digit
int(b'101', 2) # interprets as base 2 for each digit
int(b'101', 8) # interprets as base 8 for each digit
int(b'101', 10) # interprets as base 10 for each digit
int(b'101', 16) # interprets as base 16 for each digit
# String type inputs
x = '+1010' # valid +ve number string
x = '1010' # valid +ve number string
x = '-1010' # valid -ve number string
x = '+01010' # valid +ve number string
x = '01010' # valid +ve number string
x = '-01010' # valid -ve number string
int('101') # interprets as base 10 for each digit
int('101', 2) # interprets as base 2 for each digit
int('101', 8) # interprets as base 8 for each digit
int('101', 10) # interprets as base 10 for each digit
int('101', 16) # interprets as base 16 for each digit
# print(bin(int(x, 2)), int(x,2), ~int(x, 2), bin(~int(x,2)), "-"+bin((1<<k)-1 - int(x,2)))
k = 5 # no of bits
assert 2**0 == 1 # (2^0 is always 1)
_2k = (1 << k) # (2^k == left shift (2^0 or 1) by k times == multiply 2 by k times)
x = '01010' # valid +ve number string
x = int(x,2)
print("input:", x) # supposed to be 1s complement of binStr but due to python's limitation,
# we consider it -(unsigned binStr)
_1s = '-'+bin((_2k-1)-x)
print("1s complement(negate/not): ", _1s, ~x)
_2s = '-'+bin(_2k-x)
print("2s complement(1s +1): ", _2s, ~x+1)
output:
k = 5 (5 bit representation)
input: 10
1s complement(negate/not): -0b10101 -11
2s complement(1s +1): -0b10110 -10
k=32 (32 bit representation)
input: 10
1s complement(negate/not): -0b11111111111111111111111111110101 -11
2s complement(1s +1): -0b11111111111111111111111111110110 -10

Convert integer to binary in python and compare the bits

How to convert a int n into binary and test each bit of the resulting binary number?
I have just got the following after a lot of googling:
def check_bit_positions(n, p1, p2):
print int(str(n),2)
However i get an error invalid literal for int() with base 2. Let me know how can i get binary form of the input number and test each bit at position p1 and p2
EDIT:
binary = '{0:b}'.format(n)
if list(binary)[p1] == list(binary)[p2]:
print "true"
else:
print "false"
The above code works now, however how can i check for postions p1 and p2 from the end of the list?
Use bin() function:
>>> bin(5)
'0b101'
or str.format:
>>> '{0:04b}'.format(5)
'0101'
Here's a quick function I wrote to check the nth bit of a number:
def check_nth_bit(num, n):
return (num>>n)&1
Basically, you bitshift the number n times to the right, which would put the nth digit in the rightmost position, and by bitwise and-ing the new number with 1 (which is all 0's except for in the rightmost position), you can check if that bit is a 1 or a 0. So, you can call this function on num with p1 and p2 and compare the results.
EDIT: This will be p1 and p2 from the end of the number (least-significant bit), not the beginning.
You can use format:
>>> format(10, 'b')
'1010'
int is used to convert a number from any base to base 10, and you're trying to use it to convert an integer to binary which is wrong.
>>> int('1010', 2)
10
>>> int('20', 2)
Traceback (most recent call last):
File "<ipython-input-3-05fc7296a37e>", line 1, in <module>
int('20', 2)
ValueError: invalid literal for int() with base 2: '20'

Categories

Resources