Python: math.pow() vs **? [duplicate] - python

This question already has answers here:
Exponentials in python: x**y vs math.pow(x, y)
(7 answers)
Closed 3 years ago.
I've been trying to solve this problem:
The cube at the bottom will have a volume of n^3, the cube above will
have volume of (n-1)^3 and so on until the top which will have a
volume of 1^3.
You are given the total volume m of the building. Being given m can
you find the number n of cubes you will have to build?
And this is my code
import math
def find_nb(m):
nb = 1
nb_vol = 0
while True:
nb_vol += math.pow(nb, 3)
if (nb_vol == m):
return nb
elif (nb_vol > m):
return -1
nb += 1
Now, when I try to solve for find_nb(2521115597681328384) it returns -1 when it should in fact return 56352. If I change
nb_vol += math.pow(nb, 3)
to
nb_vol += nb ** 3
Everything works correctly. Why?

math.pow always converts it’s arguments to floats first, which are only approximations.
The ** operator uses integers that can never overflow, which means that it always gives a correct result.

Related

Printing binary without trailing 0s? [duplicate]

This question already has answers here:
Why does integer division yield a float instead of another integer?
(4 answers)
Closed 4 months ago.
Trying to create a small program that takes in positive integers and converts it into reverse binary.
I've gotten this far:
import math
integer = int(input())
while integer > 0:
x = integer % 2
print(int(math.floor(x)), end='')
integer = integer / 2
The problem with this is that the output would have unnecessary trailing 0s. For example, if the input is 12, the output would be 0011000......
I've tried the int function to remove floats, I also tried floor function to round up(albeit I might've done it wrong).
Could the problem be a lack of sentinel value?
It sounds like you have reversed a binary number like this:
def reverse_bits(n):
res = 0
for i in range(n.bit_length(), -1, -1):
if n & (1 << i):
res += 1 << (n.bit_length() - i)
return res
bin(reverse_bits(12)) # '0b110'
You can bit shift to the right, until there is a 1 in the rightmost bit, to remove trailing zeros:
def remove_trailing_zeros(n):
while not n & 1:
n = n >> 1
return n
All together:
bin(remove_trailing_zeros(reverse_bits(12)))
Out[11]: '0b11'
use // instead of / in division
Here is an alternate approach:
integer = 3
print (bin(integer)[2:][::-1])

Python Solution for project euler's ex 94

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)

Why is math.pow returning different values than the ** operator? [duplicate]

This question already has answers here:
Exponentials in python: x**y vs math.pow(x, y)
(7 answers)
Closed 3 years ago.
I've been trying to solve this problem:
The cube at the bottom will have a volume of n^3, the cube above will
have volume of (n-1)^3 and so on until the top which will have a
volume of 1^3.
You are given the total volume m of the building. Being given m can
you find the number n of cubes you will have to build?
And this is my code
import math
def find_nb(m):
nb = 1
nb_vol = 0
while True:
nb_vol += math.pow(nb, 3)
if (nb_vol == m):
return nb
elif (nb_vol > m):
return -1
nb += 1
Now, when I try to solve for find_nb(2521115597681328384) it returns -1 when it should in fact return 56352. If I change
nb_vol += math.pow(nb, 3)
to
nb_vol += nb ** 3
Everything works correctly. Why?
math.pow always converts it’s arguments to floats first, which are only approximations.
The ** operator uses integers that can never overflow, which means that it always gives a correct result.

Double Slash Assignment division in Python [duplicate]

This question already has answers here:
What exactly does += do?
(17 answers)
Closed 3 years ago.
I am new to Python and found a function that checks to see if an array of arguments can be made equal by only multiplying the number by 2. However, there is some notation that I do not understand.
Function:
def isEqual(a,n): # a is an arrary, n is the length of array
for i in range(0,n):
while a[i]%2==0:
a[i]//=2 # this is the part I do not understand
print(a[i])
if a[i] != a[0]:
return print("False")
# Otherwise, all elements equal, return true
return print("True")
When I step through the function I see that it replaces the a[i] number by a[i]//2, but I do not understand why you would write // equals to number
I understand the // is "floor" division, but not why someone would write a[i]//=2. I would have thought to write it as a[i]=a[i]//2. I can only assume these are the same things, I just never saw it written this way.
Test code:
a = [50, 4, 2]
n = len(a)
isEqual(a, n)
You might have came across operations that also assign value. Think
a += 1 # same as: a = a + 1
This is exactly the same. It integer divides and assigns the value. Probably better understood with proper spacing:
a //= 2 # same as: a = a // 2

Python function hangs for large numbers [duplicate]

This question already has an answer here:
Why is my function using Python time limited in input value magnatude?
(1 answer)
Closed 9 years ago.
I am trying to make a function that calculate the modular exponential MODEXP(a,e,p).
This function takes m and n as a parameters, where p is a prime number at most 2^m and e is 2^n and a is random number less than p.
Here is my code:
import random
def question_3(m,n):
list = []
i = 1
for i in range(2,2**m):
flag=True
for num in list:
if(i%num==0):
flag=False
if flag:
list.append(i)
p = choice(list)
a = randint(1,int(p)-1)
e = pow(2,n)
return pow(a, e, p)
question_3(5,5)
For m and n over 20, the code begins to hang. How do I prevent that?
If you just want to calculate
(modulus of a raised to the power e)modp
or something similar then
I would Highly recommend you this wiki article
In this case maximum number of iteration would be equal to number of bits in binary representation of variable e.

Categories