Two Complement's Python (with as least bits as possible) - python

I am trying to output the binary representation of an negative number with the least bytes available each time.
Example:
-3 -> 101
-10 -> 10110

Here's a way to do this using the .bit_length method of Python 3 integers. It also uses the string .format method to do the integer to binary string conversion. This function returns a string starting with '0' for non-negative numbers so that they can be distinguished from negative numbers.
def twos_complement(n):
m = n + 1 if n < 0 else n
bitlen = 1 + m.bit_length()
mask = (1 << bitlen) - 1
return '{0:0{1}b}'.format(n & mask, bitlen)
for i in (-10, -3, 0, 3, 10):
print('{:3}: {}'.format(i, twos_complement(i)))
print('- ' * 30)
for i in range(-15, 16):
print(i, twos_complement(i))
output
-10: 10110
-3: 101
0: 0
3: 011
10: 01010
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-15 10001
-14 10010
-13 10011
-12 10100
-11 10101
-10 10110
-9 10111
-8 1000
-7 1001
-6 1010
-5 1011
-4 100
-3 101
-2 10
-1 1
0 0
1 01
2 010
3 011
4 0100
5 0101
6 0110
7 0111
8 01000
9 01001
10 01010
11 01011
12 01100
13 01101
14 01110
15 01111
How it works
Python uses a modified form of two's complement to represent integers. Python integers have no size limit, so negative integers behave as if they have an infinite number of leading 1 bits, as explained in the Python Wiki article on Bitwise Operators.
The int.bit_length method tells us the minimum number of bits required to represent a number, we want one more bit than that so that all our non-negative numbers will start with 0 and all the negative numbers start with a 1. We need to modify that slightly to ensure that numbers of the form -2**n will only get a single leading one bit, we do that by adding 1 to all the negative numbers when calculating the bit length.
To select the bits we want we need a bit mask of the appropriate length. If the bit length is 4, we want a mask of 1111 = 2**4 - 1; we _could calculate it by using exponentiation, but it's more efficient to use bit shifting: (1 << bitlen) - 1. We then do the bitwise AND operation n & mask to select the bits we want. Fortunately, Python gives us a non-negative number when we perform such masking operations. :)
Finally we convert the resulting integer to a string using the .format method. We use a nested format specification so we can dynamically specify the correct length of the output string. In
'{0:0{1}b}'.format(n & mask, bitlen)
the first 0 of the format spec says that we're converting the value of the 0 arg in the argument list (n & mask), the :0{1}b says to convert it to binary, padded with leading zeroes if necessary, using the value of the 1 arg in the argument list (bitlen) as the total string length.
You can read about nested format specs in the Format String Syntax section of the docs:
A format_spec field can also include nested replacement fields
within it. These nested replacement fields may contain a field name,
conversion flag and format specification, but deeper nesting is not
allowed. The replacement fields within the format_spec are
substituted before the format_spec string is interpreted. This
allows the formatting of a value to be dynamically specified.

Related

How does the &= assignment operator work?

Can anyone explain me how &= assignment operator works in Python programming.
&= is a bitwise and operator. It works with the binary number. I'll explain this to you by an example
Example:
x = 5
In binary 5 is equal to 101
Now
x &= 3 which means x = x & 3
You also need to convert 3 to binary number which is 011
Now you need to apply and operator to both binary number
101
& 011
=001
So now convert this resulting binary number to decimal number which is equal to 1.
You can use online converter from decimal to binary and binary to decimal.
&= is a bitwise operator, it works with bits such as following,
a = 60 # 60 = 0011 1100
b = 13 # 13 = 0000 1101
c = 0
c = a & b; # 12 = 0000 1100
print ("c: ", c)
output:
c: 12
It works on the basis of logic given below
0&0= 0
0&1= 0
1&0= 0
1&1= 1
look at the comments i have given in the code.

Don't understand why (5 | -2) > 0 is False where (5 or -2) > 0 is True [duplicate]

This question already has answers here:
Boolean operators vs Bitwise operators
(9 answers)
Closed 3 years ago.
This is a pretty trivial question that I haven't been able to find the answer to.
Here is the problem. I have the following array:
vals = [-5, 2]
And I want to check whether val[0] or val[1] is greater than 0. If either is true, then I should output True.
My immediate thought was to use; (vals[1] or vals[0]) > 0) but I'm finding that (5 | -2) > 0 is False where (5 or -2) > 0 is True
Any clarification would be much appreciated.
What is the difference between or and |?
or is a logical or and | is a bitwise or logical inclusive or.
The logical or
The logical or in python returns the first value that is true.
Example:
>>> None or False or 5
5
>>> -5 or 2
-5
The bitwise or logical inclusive or
The bitwise or logical inclusive or is represented by the | operator in python and creates a number where all bits are set that are set in at least one of the given numbers.
Example:
2 is in binary 0010
4 is in binary 0100
A logical or between the two results in 0110 which is 6.
>>> 2 | 4
6
How a negative number is stored is generally implementation specific. However on most systems a negative number is stored by creating the two's complement of the positive number by inverting each bit and adding 1.
That number in bitwise ore two any other number still results in a negative number:
>>> -5 | 2
-5
Neither of the two solves your problem
While using
(vals[1] or vals[0]) > 0
seems to work, it fails when you flip the values:
>>> vals = [2, -5]
>>> (vals[1] or vals[0]) > 0
False
You should check both values seperatly
>>> vals = [-5, 2]
>>> vals[0] > 0 or vals[1] > 0
True
For a larger input this may be inconvenient. You should use any with a generator expression:
>>> any(x > 0 for x in vals)
True
You want the any function:
>>> any(x > 0 for x in vals)
x | y computes the bitwise OR of the two values, while x or y evaluates to the first "truthy" value. In both cases, the result is then compared to 0: (x or y) > 0 and (x | y) > 0.
What you want to compare each value to zero (as necessary), with
vals[0] > 0 or vals[1] > 0
If you had three values, you'd write
vals[0] > 0 or vals[1] > 0 or vals[2] > 0
The any function generalizes this to a list of any size, without the need to decide how many terms to or together based on the size of the list.
To answer this question, I have to explain about Two's Complement.
BINARY REPRESENTATION OF NUMBERS
So you know how internally, an integer like 5 is represented as a binary string
00000000000000000000000000000101
How do you imagine you'd represent a negative number?
Well, here's what we want to do:
Addition should work the same with negative numbers and positive numbers; i.e. you do the same steps to add 4 + 9 as 4 + -9.
Integer overflow shouldn't break mathematics; i.e. MAX_VALUE + 1 == MIN_VALUE, MIN_VALUE - 1 == MAX_VALUE
So what we do is called "Two's Complement."
TWO'S COMPLEMENT
To represent a negative number, take its absolute value, bitflip every bit, and add 1.
So if the positive number is 5
00000000000000000000000000000101
the negative number -5 is
11111111111111111111111111111011
Essentially, this means we pick the number 01111111111111111111111111111111 to be the largest positive number, and all numbers after that are negative.
SO WHAT DOES (5 | -2) MEAN?
The | is the bitwise or operator. Given two numbers, it takes every bit and or's them together, constructing a new number where a digit is 1 if the digit in that position in wither or both of the two original numbers is 1, and 0 otherwise. The calculation looks like this:
5 -> 00000000000000000000000000000101
| -2 -> 11111111111111111111111111111110
---- --------------------------------
11111111111111111111111111111111 -> -1
So as you can see, 5 | -2 = -1 < 0.
WHAT ABOUT (5 or -2)?
The "or" operator takes two values, casts them to booleans and or's them together. This is important: it doesn't or the values, it returns the first value that is "truthy" -- in other words, if you put it in an if statement, it would run.
The only integer that isn't "truthy" is 0. Therefore (5 or -2) returns the first non-zero integer of 5 and 2, which is 5 > 0. So 5 or -2 = 5 > 0.
| is a bitwise OR, and Python uses two's complement representation for integers. Evaluating 5 | -2 gives:
... 0000 0000 0000 0101 (+5)
| ... 1111 1111 1111 1110 (-2)
──────────────────────────────
= ... 1111 1111 1111 1111 (-1)
And -1 is not greater than zero, so (5 | -2) > 0 is false.
or is a logical OR. Unlike in other languages where this operator returns a Boolean (True/False) value, Python defines x or y as being equivalent to x if x else y (except that x is evaluated only once). Note that any nonzero numeric value is “truthy” in Python, so if x≠0, then x or y evaluates to x.
>>> 5 or -2
5
>>> -2 or 5
-2
That (5 or -2) > 0 evaluates to True was a stroke of luck from having the positive number first. In the other order, you would have gotten False.
In general (x or y) > 0 is not equivalent to (x > 0) or (y > 0), which is what you meant.
When you do (5 | -2), you're doing a bitwise-OR. That will preserve the negation bit in the numbers. Therefore, you'll still have a negative number.
The (5 or -2) is a logical-OR, to the Python interpreter will extend that to the next logical operator (the greater-than).
They are two completely different operations so that is expected.
To illustrate, here's a small shell log:
In [1]: 5 or -2
Out[1]: 5
In [2]: 5 | -2
Out[2]: -1
The or operator returns the first non-zero (non-None, non-False, etc.) value.
The | operator does a bitwise or. To illustrate:
In [3]: bin(5)
Out[3]: '0b101'
In [4]: bin(-2)
Out[4]: '-0b10'
In [5]: bin(5 | -2)
Out[5]: '-0b1'

Python character length of a binary value

I am looking for way to determine the number of characters my binary value takes up.
For example if my values binary values were 4, 20, and 60 I'd get the following results:
bin(4), 0b100 = 3
bin(20), 0b10100 = 5
bin(60), 0b111100 = 6
a = 20
a.bit_length()
>> 5
A positive integer n has b bits when 2b-1 ≤ n ≤ 2b – 1. So The number of bits required to represent an integer n is :
floor(log n)+1 # note that base of log is 2
And since you have 0b at the leading you need to add 2 to aforementioned formula.
So it would be :
floor(log n) + 3
And in python you can use math module like following:
math.floor(math.log(n, 2)) + 3
Example :
>>> math.floor(math.log(10, 2)) + 3
6.0
>>>
>>> len(bin(10))
6
>>> math.floor(math.log(77, 2)) + 3
9.0
>>> len(bin(77))
9
As a more Pythonic way you can also use int.bit_length which returns the number of bits needs to represent an integer object. So for get the number of require characters you can add it with 2 :
int.bit_length() + 2

How is remainder calculated with modulo when solving fractions?

As you can see, dividing 3/7 yields a fraction. But when I do 3%7 it yields 3. How could this be? I suppose I expected an output value of 4 (because it would take 4 to complete 7) or 0, (because there is no remainder at all if you use integer division such as 3//7).
>>> 3/7
0.42857142857142855
>>> 3%7
3
>>>
Just trying to understand the depths of Python. Thanks!
Remember long division? Before you learned about fractions, 50 divided by 7 would be 7, remainder 1. The remainder is the modulus. It is the numerator of the 1/7 remaining after integer division.
Let's use different numbers for demonstration.
42 divided by 5 gives a quotient of 8 and a remainder of 2. That means 42 // 5 == 8 and 42 % 5 == 2.
3 divided by 7 gives a quotient of 0 and a remainder of 3. That means 3 // 7 == 0 and 3 % 7 == 3.
In Python, // and % represent the quotient and remainder you probably learned about before you learned about fractions and real numbers. The only (possible) difference is that // floors and % matches the sign of the right-hand operand.
modulo returns the whole number after integer (floor) division.
>>>3//7
0 # with remainder 3
>>>3%7
3
>>>2//5
2 # with remainder 1
>>>2%5
1
Re-reading your question, it occurred to me you got your terms mixed up and that may have been the underlying confusion that none of us properly answered.
But when I do 3%7 it yields 3. How could this be? I suppose I expected an output value of 4 (because it would take 4 to complete 7)
So first that issue was masked when you said 4. Since 4 is greater than 3, 3 can be subtracted a second time, leaving 1. So 1 is the output of 7 % 3.
But you asked about 3 % 7, even though you then proceeded to explain 7 % 3. 3 % 7 is less than 1 (because 7 > 3). So that is why the modulus is still 3. Integer division gives you 0, so 3 is left.
Take the first term (3) divided by the second term (7) using integer division (resulting in 0). Subtract that number from the first term (3) and you get 3. So: 3 % 7 = 3

Python: Why does right shift >> round down and where should it be used?

I've never used the >> and << operators, not because I've never needed them, but because I don't know if I could have used them, or where I should have.
100 >> 3 outputs 12 instead of 12.5. Why is this. Perhaps learning where to best use right shift will answer that implicitly, but I'm curious.
Right shift is not division
Let's look at what right-shift actually does, and it will become clear.
First, recall that a number is stored in memory as a collection of binary digits. If we have 8 bits of memory, we can store 2 as 00000010 and 5 as 00000101.
Right-shift takes those digits and shifts them to the right. For example, right-shifting our above two digits by one will give 00000001 and 00000010 respectively.
Notice that the lowest digit (right-most) is shifted off the end entirely and has no effect on the final result.
>> and << are the right and left bit shift operators, respectively. You should look at the binary representation of the numbers.
>>> bin(100)
'0b1100100'
>>> bin(12)
'0b1100'
The other answers explain the idea of bitshifting, but here's specifically what happens for 100>>3
100
128 64 32 16 8 4 2 1
0 1 1 0 0 1 0 0 = 100
100 >> 1
128 64 32 16 8 4 2 1
0 0 1 1 0 0 1 0 = 50
100 >> 2
128 64 32 16 8 4 2 1
0 0 0 1 1 0 0 1 = 25
100 >> 3
128 64 32 16 8 4 2 1
0 0 0 0 1 1 0 0 = 12
You won't often need to use it, unless you need some really quick division by 2, but even then, DON'T USE IT. it makes the code much more complicated then it needs to be, and the speed difference is unnoticeable.
The main time you'd ever need to use it would be if you're working with binary data, and you specifically need to shift the bits around. The only real use I've had for it was reading & writing ID3 tags, which stores size information in 7-bit bytes, like so:
0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx.
which would need to be put together like this:
0000xxxx xxxxxxxx xxxxxxxx xxxxxxxx
to give a normal integer in memory.
Bit shifting an integer gives another integer. For instance, the number 12 is written in binary as 0b1100. If we bit shift by 1 to the right, we get 0b110 = 6. If we bit shift by 2, we get 0b11 = 3. And lastly, if we bitshift by 3, we get 0b1 = 1 rather than 1.5. This is because the bits that are shifted beyond the register are lost.
One easy way to think of it is bitshifting to the right by N is the same as dividing by 2^N and then truncating the result.
I have read the answers above and just wanted to add a little bit more practical example, that I had seen before.
Let us assume, that you want to create a list of powers of two. So, you can do this using left shift:
n = 10
list_ = [1<<i for i in range(1, n+1)] # Where n is a maximum power.
print(list_)
# Output: [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
You can timeit it if you want, but I am pretty sure, that the code above is one the fastest solutions for this problem. But what I cannot understand is when you can use right shift.

Categories

Resources