Python gives me different outputs if I add a print() later on - python

I'm super new to programming and just wanted to make something to find the approximate value of x for the equation x^3 - 1 = x. I know that -2 is greater than 0 and -1 is less. My thought is that if I find the average and check if it's greater or less than 0, I can redefine a and b and repeat until I get an approximate value. I've been having a hard time getting it to act right though. For example if I run this block without the print(i), I'll get -1.5 which would be the average, but when I put a print(total) within the function equation(n) to see if it's working right, it doesn't even show me that and just outputs -8.881784197001252e-16. If I put print(i) at the end of the if/else possibilities, such as this, it prints 16 and then -8.881784197001252e-16. I'm using PyCharm CE.
Beyond this glitch, is my logic correct? By setting the placeholder to 1 it will run the while loop. The while loop will get a new value of n and run the function, compare it to 0, then reassign a or b depending on that comparison? Thanks in advance.
a = float(-2)
b = float(-1)
n = ((a+b)/2)
print(n)
def equation(n):
total = float((n - n**3 - 1))
return total
i = 1
while i != 0:
n = ((a + b) / 2)
if (equation(n)) > 0.0:
a = n
i = equation(n)
print(i)
else:
b = n
i = equation(n)
print(i)

Moving all of the equation x^3 - 1 = x to one side should give x^3 - 1 - x = 0 or x - x^3 + 1 = 0. You have a different equation in your function.
Another problem is that there is no intersection between the two equations between x=-2 and x=-1 (see here). You'll need to expand your window to x=2 before you'll see an intersection.
Something that often happens in numerical analysis (where you'll see this type of problem) is that rather than trying to find x that actually makes the equation give 0, we look for a value of x that produces below an acceptable level of error. Another approach is to test for while b - a > tol:
If we use all of this to tweak what you've got, you'll have
a = float(-2)
b = float(2)
tol = 0.001
def equation(n):
return float(n - n**3 + 1)
n = (a + b) / 2
iter = 0
while abs(equation(n) - 0) > tol and iter < 100:
iter+=1
if equation(n) > 0.0:
a = n
else:
b = n
n = (a + b) / 2
print(iter,a,b,equation(n))
Note: this works fine if you remove the floats and just do
a = -2
b = 2
#...etc
because python already recasts values as necessary. Try
>>> type(3)
<class 'int'>
>>> type(3.5)
<class 'float'>
>>> type(float(3))
<class 'float'>
>>> type(3/5)
<class 'float'>
so python will store the result as a float as soon as it is necessary.

The immediate problem is the limited precision of floats. If you print a and b after a hundred iterations, you get:
a, b = -1.324717957244746, -1.3247179572447458
print((a + b) / 2 # -1.3247179572447458, the same as b
So at some point, b never changes, which is why you get an infinite loop. If we evaluate equation at the average of a and b, you'll get -8.881784197001252e-16, the value you were always seeing.
But this will never converge to exactly zero because the solution is irrational, so even if you had infinite precision, equation would never equal zero.
The common way to resolve this issue is to avoid comparing floats:
if a == b # don't do this
if abs(a - b) < epsilon # do this, where epsilon is some small value
(Note: what you're describing is the bisection method, which is slower than higher order algorithms e.g. Newton's method, which you can use since you can get the derivative)

Related

Is there a faster way to know if it's a real triangle?

The following code is intended to return 0 if it's not possible to form a triangle with three given sides and return 1 if it is possible. Taking into account that it's not possible for a triangle to have an area of zero or less, first I calculated the semiperimeter of this hypothetical triangle and then return 1 if the result is greater than the greatest value in the given list. I did the previous because if the semiperimeter is less than the greatest value in the list, then when calculating the area with the Heron formula it would be an undefined root.
def isTriangle(aList):
semiperimeter = (aList[0] + aList[1] + aList[2]) / 2
if semiperimeter > max(aList):
return 1
else:
return 0
So I want to know if there is a faster way in Python to perform this (or at least with fewer lines of code).
You can check if the sum of the two smaller sides is at least as large as the longest side:
def check(aList)
return sum(aList) - max(aList) > max(aList)
With python 3.8+, you can avoid recomputing the maximum twice using a walrus operator:
def check(aList):
return (m := max(aList)) < sum(aList) - m
Both solutions rely on numerical comparisons returning a big boolean. In python bool is a subclass of int that has only two possible singleton values: True == 1 and False == 0. It's standard to return a bool rather than 0 or 1 for something like this. In fact, your original conditional could be replaced by
return semiperimeter > max(aList)
Or, absorbing the previous line into the return:
return sum(aList) / 2 > max(aList)
You could also write
return sum(aList) > 2 * max(aList)
This version avoids any type conversions, regardless if whether you pass in floats or integers (/ 2 always results in a float).
You asked for shorter code. That one is possible to do as a oneliner.
def isTriangle(aList):
return ((aList[0] + aList[1] + aList[2]) / 2) > max(aList) and 1 or 0
Exatly the same code, but just written shorter
To determine if given 3 sides can form a valid triangle, I would suggest using Triangle Inequality Theorem. It roughly states that the sum of any two sides must always be equal or greater than the other side to be able to form a valid triangle.
Therefore, I would instead write something along this line. [Edited: initialization according to Avinash]
def isTriangle(aList):
a,b,c = aList
return (a + b >= c and a + c >= b and b + c >= a)
In case you really want to make it return 0 or 1 instead of boolean then you can use this return instead.
return 1 if a + b >= c and a + c >= b and b + c >= a else 0

`math.floor(1 - (1 / (float("inf"))))` doesn't return 0

I would expect
math.floor(1 - (1 / (float("inf"))))
to return 0, since any 1 - e where e is an arbitrarily small number will always be smaller than 1, which means math.floor should return 0. Instead it returns 1.
This doesn't happen because math.floor(1 / float("inf") evaluates to 0. What's a better way to achieve this desired outcome?
Further context:
I currently have the variables a and b which are floats between 0 and 1 (noninclusive), I want to know by how much to modify b such that it will change the boolean outcome of a comparison like:
a < b
E.g. if a > b == True then b += (a - b) would cause a > b to evaluate as False (success!). However, it does not work with a < b because after b += (a - b) it will be the case that a == b not that a < b. To make a less than b an additional small value e needs to be added to b as well.
Another way to ask this question is, "How do I get that small value e (epsilon) to add to b such that it will always change the value of a < b after applying b += (a - b) + e?"
You will be getting 1.0 as the answer, not 0. This is because 1/inf will be taken as 0 and not something which is a small number. So 1-0 will result in a number with no floating points, and that's why even when you use floor or ceil you will get 1.0 in this case but if you want to achieve the return value of 0 you can use any other number instead of inf.
It will solve your problem.
https://docs.python.org/3/library/math.html#math.nextafter
and
sys.float_info.epsilon
Should help

Power function from math module seems to stop working in Python

So i'm trying to write a program which finds a Pythagorean triplet, checks if all the numbers which make up the triplet add up to 1000, and if they do then multiply the 3 numbers together and output the result. Here is my sample code:
import math
numbers = [1,2,3]
found = False
while not found:
if (math.pow(numbers[0], 2) + math.pow(numbers[1], 2)) == (math.pow(numbers[2], 2)): #Checks to see if its a pythag triplet
total = 0
for x in numbers:#adds the 3 numbers together
total += x
if total == 1000: #if the total of the three numbers is 1000, multiply them all together
product = 1
for y in numbers:
product *= y
print (product)
found = True #print the product total and end the while loop
else:
numbers = [z+1 for z in numbers] #if the total isnt 100, then just add 1 to each of the three numbers
print (numbers)
else:
numbers = [z+1 for z in numbers]#if the three numbers arent pythag triplet, then add 1 to each number
When the first triplet has been found the program seems to stop working. It dosnt seem to be able to identify any pythag triplets anymore, so I guess this is due to the "pow" function not working correctly anymore? I am new to programming so would appreciate any advice on how to overcome this and also how I could improve efficiency aswell!
Turns out, your math is incorrect.
On each iteration, every number in the triplet is increased by 1
After a iterations, in order for it to be a Pythagorean triplet, the following must hold true:
(a + 1)**2 + (a + 2)**2 == (a + 3)**2
Here 1, 2 and 3 inside the parentheses are the initial contents of the list numbers.
This simplifies to 2 * a**2 + 6 * a + 5 == a **2 + 6 * a + 9
Which is true only for a == 2
So, your code executes print (numbers) on the third (a + 1) iteration and will never terminate since a is always increasing.
Your algorithm is running an infinite loop. The condition leading to found = True is never met, so it just keeps running.
The condition to print something ((math.pow(numbers[0], 2) + math.pow(numbers[1], 2)) == (math.pow(numbers[2], 2))) just happens once, as you see printed on your screen.
You should add debug output to see what your algorithm does.
Are you sure there are integers with:
n^2 + (n+1)^2 = (n+2)^2
3*n +3 = 1000
If not, the loop won't stop. The second condition can be re-written as n = 1000/3 -1. It is not an integer, so the program is never stopping. But I suspect the first equation also have a single solution, for n=3.

integer part of the root withot using functions

The calculation of the integer part of the square root of a number can be done by trial and error, starting from 1, by executing the square until the result is less than or equal to the starting value of which is calculated by the root.
The following program returns the integer part of the root
def radice(x):
z = 0
t = 0
while True:
t = z*z
if t > x:
z -= 1
return z
z += 1
radice(17) // 4
Will be possible to write it without using functions and break?
Here is my code witout function but I dont' know how to write the same algo with no break
z = 0
t = 0
while True:
t = z*z
if t > x:
z -= 1
break
z += 1
print 'The integer part of the root is: ', z
This should suffice:
>>> int(17**0.5)
4
17**0.5 generates the square root of 17, and int basically removes the decimals, leaving you with the "integer part of the root".
Without using any functions, and if you want an integer result, complex code (like your own) is needed. However, if a float will do, then you could try this:
>>> (17**0.5)//1
4.0
This essentially does the same as the int call, but will return a float if either side is a float.
As you said the integer part of the square root of a number can be done by trial and error, starting from 1, by executing the square until the result is less than or equal to the starting value of which is calculated by the root.
Said that you can write the code without using function and break statements; here is the code:
n = input("insert a number: ")
r = 1
while (r * r <= n):
r = r + 1
print "the result is:", r -1
Parens are for clarity, not required
>>> (17**.5)-(17**.5)%1
4.0
Ok, let's think logically.
You cannot use break, so the only way to get out of the while loop is to break its condition.
If it's True, it cannot be broken, so we have to think about the proper condition to stop iterating. And this condition is already used in your algorithm: you exit when t > x, or z * z > x. So the condition to continue iteration should be the opposite, i.e. z * z <= x. And we have this simple solution.
x = 17
z = 0
while z * z <= x:
z += 1
print 'The integer part of the root is: ', z - 1
As a general rule, try to shy away from those while True: loops. While they are sometimes useful, they're generally harder to read and understand, this is probably why your teacher limits the use of break. The function was prohibited probably because return is just another way of escaping the loop. But those are exceptional: the normal way to end a loop is to break its condition, so this is how it should be written.

Why is my recurssion not working? Warning: Project Euler spoiler

I'm not quite sure why my recursive algorithm is not working. I get the below error but, i guess in my mind it appears i have a termination point. I know I am forgetting something simple.
RuntimeError: maximum recursion depth exceeded
def triplet(n):
a = (2*n) +1
b = (2*n)*(n+1)
c = (2*n)*(n+1) +1
if a+b+c == 1000:
return a*b*c
elif a+b+c > 1000:
return 'no triplet found'
else:
return triplet(n+1)
print triplet(1)
You are using a variant of Euclid's method for generating triples. However, it does not produce ALL possible triples, and so it clearly not generating the triples that are needed to solve your problem.
In fact, there is no universal formula for generating all Pythagorean triples. You'll need to either analytically find the solution or brute force it.
Check for greater then or equals
def triplet(n):
a = (2 * n) + 1
b = (2 * n) * (n + 1)
c = (2 * n) * (n + 1) + 1
if a + b + c >= 1000:
return a * b * c
else:
return triplet(n + 1)
print triplet(1)
Are you sure recursion/euclid's method is the best way to go about doing this one? I remember doing this by holding the sum equal to 1000, and then varying the two independent variables and checking when they were equal. (I also used some sort of the triangle inequality to decrease the number of solutions to check, but that is not necessary as at most you'll be checking 1 million possibilities).

Categories