I have the following code in Python:
for i in range(4):
if self.start == self.corners[i]:
self.visitedCorners += (1 << i)
I'm working with co-ordinates. self.start and self.corners are co-ordinates.
So with the code on the top I want to check whether the start is a corner.
If the start is the same of a corner, I do that shift. But, how does that shift work?
I don't want any other code; I just want to understand this code.
All that 1 << i does is produce the number with the i-th least significant bit set to 1 and all other bits set to 0:
>>> for i in range(4): print bin(1 << i)
...
0b1
0b10
0b100
0b1000
In the code, self.visitedCorners is a bit mask, where the four least significant bits correspond to the four corners. Each iteration of the for i loop sets the corresponding bit in self.visitedCorners to 1 (provided the if condition holds).
Related
Note: This is a revised version of a post I made some days ago that was closed due to incompleteness. I have now done my best to optimise it, and it should now be a minimal reproducible example.
The question:
"It is easily proved that no equilateral triangle exists with integral length sides and integral area. However, the almost equilateral triangle 5-5-6 has an area of 12 square units.
We shall define an almost equilateral triangle to be a triangle for which two sides are equal and the third differs by no more than one unit.
Find the sum of the perimeters of all almost equilateral triangles with integral side lengths and area and whose perimeters do not exceed one billion (1,000,000,000)."
The answer to the problem is 518408346.
My result is much larger than this number. How come? After looking through the comments on the previous post prior to its suspension, I believe that it is due to a floating-point error.
I assume that my code generates numbers that are border-line integers which Python falsely takes for integers. That would explain why my result is much larger than the correct. I have observed that python does this when the number of leading zeros after the decimal point exceed 15 (e.g., 3.0000000000000005 is taken as 3.0000000000000005 whereas 3.(>15x 0) is taken as 3.0. If there was a way to change this setting, my method could work. Do you agree? I have thought that the module, decimal, could prove useful here, but I am not sure how to utilize it for this purpose.
This is my code:
sum_of_p=0
for i in range(2,333333334):
if i%(5*10**6)==0:
print(i)
h=(i**2-((i+1)*0.5)**2)**0.5
if int(h)==h:
a=0.5*(i+1)*h
if int(a)==a:
sum_of_p+=3*i+1
h=(i**2-((i-1)*0.5)**2)**0.5
if int(h)==h:
a=0.5*(i-1)*h
if int(a)==a:
sum_of_p+=3*i-1
print(sum_of_p)
I assume that using floats is not a good idea for integer values problem. Here is solution that I have found. If your version or python is below 3.8, then you will have to use more slow is_square_ function
import math
def is_square_(apositiveint):
# Taken from:
# https://stackoverflow.com/questions/2489435/check-if-a-number-is-a-perfect-square
x = apositiveint // 2
seen = set([x])
while x * x != apositiveint:
x = (x + (apositiveint // x)) // 2
if x in seen: return False
seen.add(x)
return True
def is_square(i: int) -> bool:
return i == math.isqrt(i) ** 2
def check(a, b, c):
""" return preimeter if area of triangle with sides of lengts a,b,c is integer """
perimeter = a + b + c
if perimeter % 2 == 1:
# preimeter should be even
return 0
p = perimeter // 2
# Use Heron's formula
H = p*(p-a)*(p-b)*(p-c)
if is_square(H):
return perimeter
return 0
sum_of_p = 0
max_i = 1000000000 // 3
for i in range(2, max_i + 1):
if i % (10**5) == 0:
print(i*100 / max_i )
sum_of_p += check(i, i, i+1)
sum_of_p += check(i, i, i-1)
print(sum_of_p)
I understand what each of the individual operators does by itself, but I don't know how they interact in order to get the correct results.
def kill(n, k):
#Takes int n and replaces the bit k from right with 0. Returns the new number
return n & ~(1<<k-1)
I tested the program with the n as 37 and k as 3.
def b(n,s=""):
print (str(format(n, 'b')) +" "+ s)
def kill(n, k):
b(n, "n ")
b(1<<k-1, "1<<k-1")
b(~(1<<k-1), "~(1<<k-1) ")
b( n & ~(1<<k-1)," n & ~(1<<k-1) ")
return n & ~(1<<k-1)
#TESTS
kill(37, 3)
I decided to run through it step by step.
I printed both the binary representations of both n and ~(1<<k-1) but after that I was lost. ~(1<<k-1) gave me -101 and I'm not sure how to visualize that in binary. Can someone go through it step by step with visualizations for the binary?
All numbers below are printed in binary representation.
Say, n has m digits in binary representation. Observe that n & 11...1 (m ones) would return n. Indeed, working bitwise, if x is a one-bit digit (0 or 1), then x & 1 = x.
Moreover, observe that x & 0 = x. Therefore, to set up kth digit of number n to 0, we need to do operation and (&) with 11111..1011..1, where 0 is exactly on kth location from the end.
Now we need to generate 11111..1011..0. It has all ones except one digit. If we negate it, we get 00000..0100..1 which we get by 1 << k-1.
All in all: 1 << k-1 gives us 00000..0100..0. Its negation provides 11111..1011..1. Finally, we do & with the input.
I encountered such a function:
import math
import random
def low_zeros(value):
for i in xrange(1, 32):
if value >> i << i != value:
break
return i - 1
I googled but not found any useful material about value >> i << i != value:
It's checking how many right-side bits are set to zero.
>> bitshifts right, then << bitshifts left by the same amount. Consider:
0b1000 >> 3 << 3
the first shift will do 0b1000 -> 0b0001. The second will do 0b0001 -> 0b1000. That's still equal to the original, so we're set.
Now let's see
0b1000 >> 4 << 4
the first shift will do 0b1000 -> 0b0000 because it shifts the one off the right side of the number. The second shift will try to shift back, but there's nothing to shift (0 << n == 0 for any natural number n). The function is left to compare 0 != 0b1000 and of course breaks execution of the for block.
The function then returns 4-1, which is 3, which is how many zeroes are on the right side of the number.
Please help in understanding the logic behind the following function:
def bit_rev (x, b): # reverse b lower bits of x
return sum (1<<(b-1-i) for i in range (0, b) if (x>>i) & 1)
I took a look at the code and it doesn't seem to account for bits past the b'th bit. So, I added another addition. (Unless all you want is up to the b'th bit):
def bit_rev (x, b): # reverse b lower bits of x
return (x >> b << b) + sum(1 << (b - 1 - i) for i in range (0, b) if (x >> i) & 1)
Now for the explaining the logic.
x >> b << b
So, let's say we're using 5 (as x) in this example with 2 as b.
The binary representation of 5 is 101. So, we want to switch only the last 2 bits. Which is 01. However, in our other code we are swapping them, but we are ignoring the bits past b. So, we are ignoring the first (from left to right) 1.
Now the first operations:
x >> b in our case is 5 >> 2. 101 moving to the right 2 is 1, since we end up chopping off the 01.
Next we shift it back. We are guaranteed (in Python) to get 0's back from the bit shift, so we now have 100, or 4.
Now for the meaty part,
sum(1 << (b - 1 - i) for i in range (0, b) if (x >> i) & 1)
It's probably would be easier to understand this outside of a list comprehension, so I rewrote it as a for-loop.
summation = 0
for i in range (0, b):
if (x >> i) & 1:
summation += 1 << (b - 1 - i)
Basically on each iteration we are finding the reverse bit an then adding it to the total (summation).
This code seems to be kind of difficult to understand because there is a lot going on.
Let's start with the for loop itself. for i in range (0, b) is iterating over all values between 0 and b. (Or the last bit you want to change). All the reversing happens later on in the code.
Next we check to see if the bit we are going to swap is a 1. In binary only 1's add value to the total number, so its logical to ignore all 0's. In if (x >> i) & 1:. We bitshift x to the right i bits. So, 101 bit shifted to the right 1 bit is 10. We now check to see if that last bit is a 1 by doing & 1. Basically what & 1 does in this program is ignore all bits beyond the first bit.
The and bitwise operator works as follows:
0101
&1100
=0100
And requires both to be true. Since all bits past 1 would be 0, it effectively ignores the rest.
Now we get a 0 or a 1 from (x >> i) & 1 and Python processes all non-zero integers as True and zero as False. This will make use ignore all bits that are zero.
Next, we add to summation using: summation += 1 << (b - 1 - i). We get the location of where it the bit is going to be by using b - 1 - i. Then we shift 1 over to that location and then add it to the total.
When adding two binary integers, you can add a 1 to a location in the number similar to how you would base 10. So, if I had the number 9000 and I wanted a 1 in the hundredths digit I could do 9000 + 100. That is similar to what we are doing here. We are moving it over to the left in base 2 by using the << operator instead of taking 10^i. So we are setting the newly reversed bit to whatever the original bit was.
I am doing an assignment where I have to institute the Diffie-Hellman key exchange. In order to speed things up I am using bit-operators in Python, and everything is working fine programming wise, but I have to perform a Parity Checksum, and I don't think I have the proper understanding of what this is or how it works.
Basically I need to be able to take a key of variable length (up to 2048 bits), break it into 64 bit words, and perform Checksum. I am unsure what this means exactly. To break a word into 64 bit words using Python, how would one go about that? I think once I do that I should be able to just perform an XOR operation on the words to get a 64bit output. At the moment though I am stuck on exactly how one break up a word in 64 bit chunks in Python appropriately?
A parity checksum is just the xor of all the bits in the word. The most efficient way to do this will have log(nbits) operations, because you can halve the number of bits you are dealing with on each iteration. For example:
def parity(word, nbits):
if nbits & (nbits - 1):
raise ValueError("nbits must be power of two")
while nbits > 1:
nbits >>= 1
word ^= (word >> nbits)
return word & 1
A longitudinal parity check is a bit different, because you stop when you get to a given word-size, at which point, your parity should be all zeros or all ones, rather than a single one or zero. I don't know whether you want odd or even parity, so this is a bit more general:
def longitudinal_parity(data, total_bits, word_bits, expected_parity=1):
"""
Performs longitudinal parity check
"""
for nbits in (total_bits, word_bits):
if nbits & (nbits - 1):
raise ValueError("bit size must be power of two")
mask = (1 << total_bits) - 1
while total_bits > word_bits:
total_bits >>= 1
data ^= (data >> total_bits)
mask >>= total_bits
data &= mask
return data == (mask if expected_parity else 0)
So for your example, the first parameter would be a 2048 bit integer, the total_bits would be 2048, the word_bits would be 64, and the desired parity would be 0 or 1.
I don't know anything about Diffie-Hellman's parity check, but if your parity is provided separately (seems likely), then you are comparing against a separate parity word rather than all ones or all zeroes. This is a minor tweak:
def longitudinal_parity(data, total_bits, word_bits, expected_parity):
"""
Performs longitudinal parity check
"""
for nbits in (total_bits, word_bits):
if nbits & (nbits - 1):
raise ValueError("bit size must be power of two")
mask = (1 << total_bits) - 1
while total_bits > word_bits:
total_bits >>= 1
data ^= (data >> total_bits)
mask >>= total_bits
data &= mask
return data == expected_parity
There are plenty of possible optimizations here, such as precalculating masks, starting the mask off at a smaller number, etc. Hopefully the code is readable.