Learning bitwise - python

I am having a hard time trying to figure out why I am getting the result with my code that I am getting.
c = int(format(ord('c'), 'b'))
h = int(format(ord('h'), 'b'))
result = c | h
print(c)
print(h)
print(result)
This returns a result of:
1100011
1101000
1101035
So my question is after the | operation, why is it 1101035 when (according to my understanding) it should be 1101011?

The call to format with the second argument being "b" gives you the binary representation of the number in the first argument. So, if you print it, you will see the "0"s and "1"s.
However, when you use int on this result, withug informing int that your string is base 2, it thinks these are decimal numbers. So, it will "read" the sequence "1100011" (the binary representation of 99, the unicode codepoint for the "c" character), as "1_100_011", or "one million, one hundred thousand and eleven" - and that is the number in your c variable if you print or make any numeric operations with it.
This can be easily solved by telling int that the numeric strings you are reading are binary themselves:
c = int(format(ord('c'), 'b'), 2)
(Passing 2 as the second argument to "int" to indicate the base). If you inspect "c" at this point, it contains the number 99, which will behave as expected with your "|" operator. Of course, if you are not looking at the binary representation of the number, there is no point in generating it to start with, so your code could be just c = ord('c')...

Doing int() here makes no sense (it's taking your string of binary bits and interpreting them as a decimal number). You just want:
c = ord('c')
h = ord('h')
result = c | h
print(format(c, 'b'))
print(format(h, 'b'))
print(format(result, 'b'))
(only using format for display on screen, not for calculation!)
which prints:
1100011
1101000
1101011

Related

Python: Space floats in long string

I am producing a large output file, which goes over several lines. This is a shortened version of a section I hope to produce.
line = \
f"""
Output: {a} {b:0.10f} {c:0.8f}
"""
where a, b, and c are floats of variable length.
In the example above, I have managed to shorten the b float and c float to 10 decimal places and 8 decimal places respectively.
However, I am hoping to get a string which when printed looks like:
Output: 10.05 0.0987654321 0.87654321
Where the spacing between the values can be controlled individually and is not necessarily equal. Essentially, I hope to lock the values in position.
This is made difficult by the fact that a could also be a tuple of varying length (which impacts the positioning of the floats).
Is this possible without the .format() method?
If not, how should the .format() method be used correctly?
Put the space before the specifier and drop the 0 prefix for the float
The value before the . is the padding and position, and not necessarily the 0-prefix for a float
>>> f"Output: {a} {b:.10f} {c:.8f}"
'Output: 10.05 0.0987654321 0.87654321'
>>> f"Output: {a: <5} {b: >15.10f} {c:0>15.8f}"
'Output: 10.05 0.0987654321 000000.87654321'

Formatting a float number without trailing zeros

When I do a simple division in Python 3, such as 123000/1000, I get 123.0, or 4/2 I get 2.0. How do I get rid of the trailing zero in Python 3's division?
EDIT:
I don't want just simple integer division. For ex, 1234/1000 should give 1.234.
To be clear, this question is about formatting the output, not internal representation.
Thanks all for your help! The answer came from #vaultah:
>>> f'{2.1:g}'
'2.1'
>>> f'{2.0:g}'
'2'
So just use regular division such as 4/2 and then format the string.
From the docs for 'g': https://docs.python.org/2/library/string.html#format-specification-mini-language
"insignificant trailing zeros are removed from the significand, and the decimal point is also removed if there are no remaining digits following it."
You could use something like this:
def remove_trailing_zeros(x):
return str(x).rstrip('0').rstrip('.')
remove_trailing_zeros(1.23) # '1.23'
remove_trailing_zeros(4.0) # '4
Normally, you would use standard string formatting options like '%2.1f' % number or any of the other many ways to format a string. However, you would then have to specify the amount of digits you want to display but in this case the number of trailing zeros to return is variable. The '%g' format specifier does not have this problem, but uses scientific notation and I don't know if that is what the OP wants.
The above solution converts the number to a "nicely printable string representation" (str(x)), and then removes trailing zeros (.rstrip('0')) and if necessary the remaining trailing period (.rstrip('.')) (to avoid "1." as a result) using standard string methods.
It's "correct" behaviour to have "floats" as a result, and .0 part simply indicates this fact. I think that what matter to you is "representation" of the result in the string. So you should not change actual result and only change the way it's "displayed". Use formatting mini language:
>>> for val in (123000/1000, 4/2, 1234/1000): print(f"{val:g}") # Use "General format" to represent floats
...
123
2
1.234
Mod is an O(1) operation which should add almost no overhead to your actual program. You could make it into a one liner also
x = a//b if not a % b else a/b
If you need to do this kind of thing a lot, make it into a function
def func(a, b):
return a//b if not a % b else a/b
func(10, 2) # out = 5
func(10, 3) # out = 3.333333333
func(1200, 100) # out = 12
func(1234, 1000) # out = 1.234
This works well for me. No scientific notation format for big numbers.
def no_trailing_zero(value: float) -> Union[float, int]:
return int(value) if value % 1 == 0 else float(str(value))
>>> no_trailing_zero(50)
50
>>> no_trailing_zero(50.11)
50.11
>>> no_trailing_zero(50.1100)
50.11
>>> no_trailing_zero(50.0)
50
>>> no_trailing_zero(500000000.010)
500000000.01
>>>
If you can guarantee that you get just a trailing zero, casting to int gets rid of it:
>>> 4/2
2.0
>>> int(4/2)
2
# // => used for integer output
# / => used for double output
x = 100/35 # => 2.857142857142857
y = 100//35 # => 2
z = 100.//35 # => 2.0 # floating-point result if divisor or dividend real

Extracting runtime number of bits from integer

I need to extract some bits from an integer. However how many bits to be extracted is not fixed.
For example a certain code is generating 2 numbers a and b. What I want is a code that could do
c = a[b-1:0]
One of the methods I read about on the web is w say b is a fixed value 3, a simple method to do is
c=bin (a >> 0 & 0b111 )
But this could be done if value of b is fixed 3 i.e we right shift based on known fixed number of bits being anded i.e 3.
But what if the "3" is not fixed? During run time I may need lower 4 bits or 3 bits or 2 bits...anything.
I thing I tried and hoped it would work is
x = bin(a)
c= x[b-1:0]
But even this doesn't work.
Some of your code is trying to access the bits of an integer using slice notation ([:]) but that only works with sequences, not integers.
First you need to decide if you want to work with a string representation of your number in binary, or an integer representation, and be consistent about that. Let's start with a string representation in binary. a is the input number, b is the number of bits.
>>> a = 35
>>> x = bin(a)
>>> x
'0b100011'
Now you want a string representation in binary of the integer that is the rightmost b positions of this string:
>>> b = 3
>>> x[-b:]
'011'
Deprived of its 0b prefix, this string of 3 digits could mean anything. Some examples: in binary, 3; in decimal, 11; in octal 9; in hex, 17. We know from reading the code that it is part of the output from a bin() call, but the string doesn't carry that information around with it. The 3 digits mean whatever you intend them to mean.
If you want to convert that into something you can do arithmetic with, you call int() to convert it back to an integer. But because int() can't tell that the representation is supposed to be binary, do this:
>>> int(x[-b:],2)
3
The 2 passed as the second parameter to int() specifies what base the string is supposed to be in. It's not specifying a conversion: it's specifying an interpretation. It's optional, but if you leave it out then int() will use the default base, which is of course 10.
>>> int(x[-b:])
11
This happens because without any indication of the base, 011 means "eleven, with a leading zero". And int() converts a string to an integer: just integer, not base-10 integer. The internal representation of integer is only converted to base 10 when you ask the interpreter to display it. (Internally, Python integers actually use base 2**30, but most of us never have to think about that much, and I recommend you don't either.)
Now consider just working with integers. If the number of bits you want to mask off is b then (as johnrsharpe points out), you can get the corresponding mask using (2**b - 1):
>>> 2**b - 1
7
Just to demonstrate this is what you actually want:
>>> bin(2**b - 1)
'0b111'
Then you can use the bitwise & operator to get the digits you want. This works sort of opposite to the string method: instead of chopping off the 3 digits that you want, you instead use & to set the digits you don't want to zero:
a = 100011
b = 000111 &
------
000011
Then you can obtain the result directly without having to go through a string conversion and taking slices and converting back to integer:
>>> a & 2**b - 1
3
As you can see this gives the same result in one step. In your question I also see a right shift operator >> but because you are shifting zero positions it does nothing. If you also want to accept a shift quantity, say s, then in the examples above, use (a >> s) instead of a.
From the question, it is not very clear what you actually want to do, but what I understood is that you want to extract 'b' last bits from 'a'.
If two numbers are 'a' and 'b':
First, convert 'a' into binary:
x = bin(a)[2:]
Extracting last b bits from a:
p = x[len(x)-b:]
If you actually want the (lower) bits of the integer value: something like this could do it:
def getbits(value, numbits):
""" Extract the lower numbits of value. """
return value & (2 ** numbits - 1)
value = 0b010011000111
for i in range(value.bit_length()+1):
print('getbits({:012b}, {:2d}): {:12b}'.format(value, i, getbits(value, i)))
Output:
getbits(010011000111, 0): 0
getbits(010011000111, 1): 1
getbits(010011000111, 2): 11
getbits(010011000111, 3): 111
getbits(010011000111, 4): 111
getbits(010011000111, 5): 111
getbits(010011000111, 6): 111
getbits(010011000111, 7): 1000111
getbits(010011000111, 8): 11000111
getbits(010011000111, 9): 11000111
getbits(010011000111, 10): 11000111
getbits(010011000111, 11): 10011000111

Converting Ints into binary / hex with ^ operator

I have two variables, Read and Out.
Read is a string e.g. "1101", Next there is Out which will be an int following the same binary format such as 100000 etc. I need to perform an operation so that If my two variables are
>>1000
>>1011
Output: 0011
I have tried to use Read ^ Out, I have tried to convert them to hex and do that but they always turn out as ints with other numbers ( 2-9 ). Output needs to be Int or a binary literal ( 0b0101 )
edit: This value is then sent off to another function like so Write( 0x20, 0x13, Out ). Whenever it gets sent Python automatically converts it to an int if its a binary, which causes problems later on.
^ works on ints.
You can convert strings to integers with a specified base:
int(x=0) -> integer
int(x, base=10) -> integer
For the opposite conversion there's bin().
In [1]: bin(int('1000', 2) ^ int('1011', 2))
Out[1]: '0b11'
The rest is a matter of string formatting. If you want to always have it in four digits and without the prefix, take a look at arshajii's answer.
I believe you're looking for a format operation in addition to ^:
>>> a = int('1000', 2)
>>> b = int('1011', 2)
>>> format(a ^ b, '04b')
'0011'
Notice that 11 in binary is equal to 0011:
>>> int('11', 2) == int('0011', 2)
True
It just comes down to how the number is represented as a string.
Use int() with a base of 2 to convert both variables:
>>> bin(int("1000", 2) ^ int(1011, 2))
>>> 0b11

Appending ten digit integer to list concatenates some entries with an "L"

I wrote a small script to find n-digit primes in the digits of e (in relation to that old Google ad):
import math
# First 251 digits of e
e_digits = ("2"
"7182818284 5904523536 0287471352 6624977572 4709369995"
"9574966967 6277240766 3035354759 4571382178 5251664274"
"2746639193 2003059921 8174135966 2904357290 0334295260"
"5956307381 3232862794 3490763233 8298807531 9525101901"
"1573834187 9307021540 8914993488 4167509244 7614606680")
e_digits = e_digits.replace(" ", "")
digits = int(raw_input("Number of digits: "))
print "Finding ", str(digits) + "-digit primes in the first", len(e_digits), "digits of e."
numbers = []
primes = []
# Creates list of numbers based on variable digits
for n in range(0,len(e_digits) - (digits - 1)):
test_number = e_digits[n:n+digits]
numbers.append(int(test_number))
# Checks each number for divisors smaller than its sqrt, then appends to list primes
for n in numbers:
n_sqrt = int(math.floor(math.sqrt(n)))
div = []
for i in range(2,n_sqrt+1):
if n % i == 0:
div.append(i)
if div == []:
primes.append(n)
print primes
However, when I set digits = 10, this is printed:
[7427466391L, 7413596629L, 6059563073L, 3490763233L, 2988075319L, 1573834187, 7021540891L, 5408914993L]
All of the list entries except for number six has been concatenated with an "L", and I have no clue why. The problem arises when I run the code in IDLE as well as in CMD, though only when appending ten digit integers using this specific code.
In the if-statement in the last for loop, the correct numbers are printed if I print n, or if I convert n to a string before appending. However, then converting to a integer again creates the same problem.
The problem also occurs with digits = 11, but not with digits < 10.
I cannot for the life of me find the error (or figure out if there is an error at all, really). Some advice on this would be greatly appreciated.
Your code is working just fine and what you see is normal. Those are literal representations of Python long integers.
When printing a list, the contents of a list are printed as representations, the same output as the repr() function would give. The alternative is to print individual elements of the list instead.
You don't need to worry about the long representation, however. That is just an implementation detail of Python integers leaking through:
>>> 1234567890
1234567890
>>> type(1234567890)
<type 'int'>
>>> 12345678901234567890
12345678901234567890L
>>> type(12345678901234567890)
<type 'long'>
Here, the Python interpreter prints the results of expressions as repr() representations too. Integers larger than sys.maxint automatically become long integers.
Quoting the documentation:
Plain integers (also just called integers) are implemented using long in C, which gives them at least 32 bits of precision (sys.maxint is always set to the maximum plain integer value for the current platform, the minimum value is -sys.maxint - 1). Long integers have unlimited precision.
and
Unadorned integer literals (including binary, hex, and octal numbers) yield plain integers unless the value they denote is too large to be represented as a plain integer, in which case they yield a long integer. Integer literals with an 'L' or 'l' suffix yield long integers ('L' is preferred because 1l looks too much like eleven!).
Comparisons and arithmetic between regular and long integers is fully supported and transparent:
Python fully supports mixed arithmetic: when a binary arithmetic operator has operands of different numeric types, the operand with the “narrower” type is widened to that of the other, where plain integer is narrower than long integer is narrower than floating point is narrower than complex. Comparisons between numbers of mixed type use the same rule.
Python 3 removed the distinction altogether.

Categories