Issues with while loop - python

So this code is meant to return the final error and the final logarithm of a number inputted by a user. Now my issue is that it doesn't run the loop, it just keeps going over the same number and it never ends. I am not sure if I have my print statements in the wrong area, or if I am doing the loop wrong but I want the loop to end when the error is less then 1x10^-9. It's possible my iterations are set up wrong too, not really sure what I messed up on here.
import math
import sys
#Computing natural log of x
#x value is input here
x = float(input("Please input a positive number: "))
#If x is not positive then program will not work, so it will exit
if x<=0:
print("Your number is not positive. System Shutdown.")
sys.exit()
#Retrieving ln(x) using the math command
lnx0 = math.log(x)
#Formula for approximate ln
xfrac = (x - 1)/(x + 1)
lnx = 0 #Initializing the approximating
i=0
#This is the code to make it go until it hits the error we want
while True:
ex = 2*i - 1
lnx += 2.0* (xfrac**ex / ex)
#Counter adding 1 to it
i+=1
#This is the error
err = math.fabs(lnx0 - lnx)
if err<0.0000000001:
break
#Priting approximate ln at end of loop
print ("ln(x) at " ,x,"is: " ,lnx)
#Final Error
print ("Final error is:" ,err)
#Number of itterations
#Printing accurate version of ln(x) just to see what it should be
print ("Your accurate value of ln(x) is: " ,lnx0)

I'm assuming you're using the fourth formula on this page to approximate the log function. If so, your i is starting at the wrong value; you've initialized it to 0 here, but it needs to start at 1.
Also, if you only want output after the answer has been found, rather than once per iteration, your print functions should be de-indented so they are outside the loop. Try:
import math
import sys
#Computing natural log of x
#x value is input here
x = float(input("Please input a positive number: "))
#If x is not positive then program will not work, so it will exit
if x<=0:
print("Your number is not positive. System Shutdown.")
sys.exit()
#Retrieving ln(x) using the math command
lnx0 = math.log(x)
#Formula for approximate ln
xfrac = (x - 1)/(x + 1)
lnx = 0 #Initializing the approximating
i=1
#This is the code to make it go until it hits the error we want
while True:
ex = 2*i - 1
lnx += 2.0* (xfrac**ex / ex)
#Counter adding 1 to it
i+=1
#This is the error
err = math.fabs(lnx0 - lnx)
if err<0.0000000001:
break
#Priting approximate ln at end of loop
print ("ln(x) at " ,x,"is: " ,lnx)
#Final Error
print ("Final error is:" ,err)
#Number of itterations
#Printing accurate version of ln(x) just to see what it should be
print ("Your accurate value of ln(x) is: " ,lnx0)
Result:
Please input a positive number: 5
ln(x) at 5.0 is: 1.6094379123624052
Final error is: 7.169509430582366e-11
Your accurate value of ln(x) is: 1.6094379124341003
Thanks to DSM for identifying the formula and possible fix

There are several problems with this. The first is that your computations are incorrect. I tried entering 'e' to 9 places. Your estimate, lnx, quickly degenerates to -3.3279+ and sticks there. This dooms you to an infinite loop, because the estimate will never get near the true value.
Others have already pointed out that you haven't traced your computations with print statements. I'll add another hint from my days in numerical analysis: use a restricted "for" loop until you've debugged the computations. Then trade it in for a "while err > tolerance" loop.
To address your most recent comment, you're not getting the same numbers. The first few terms are significant, but the infinite sequence quickly drops close to 0, so the additions don't show up after about 15-20 iterations.
Also print out ex and lnx values within the loop. Especially check the first one, where your exponent is -1; I believe that you've started the loop in the wrong place.
Finally, you might find this loop form a little easier to read. Get rid of your if...break statement and use this instead:
i = 1
err = 1
tolerance = 1e-10
# This is the code to make it go until it hits the error we want
while err >= tolerance:

Related

A program that uses while loop to find average of numbers inputted, and uses a break statement to exit the loop

I would like to write a program that uses a while loop to repeatedly prompt the user for numbers and adds the numbers to a running total. When a blank line is entered, the program should print the average of all the numbers entered. I also would like to use a break statement to exit the while loop.
My Incorrect Work:
y = "\n"
total = 0
k = 0
while True:
x = input("Enter your number here: ")
x = float(x)
total = total + float(x)
k = k + 1
if type(x) != int:
print(total/k)
break
Be aware that the function input() will always outputs a string, so type(input()) != int will always be true.
Try using try-except function, when there is ValueError (example unable to convert blank/letters to float), the exception will be raised and break the loop:
total = 0
k = 0
while True:
x = input("Enter your number here: ")
try:
total += float(x)
k += 1
except ValueError:
if k > 0: #to avoid division by zero
print("Average: ", total/k)
break
Output:
Enter your number here: 3
Enter your number here: 4
Enter your number here: 5
Enter your number here:
Average: 4.0
Bearing in mind the comments already made, here is one such way to perform your task and finishing up when a blank entry is encountered.
total = 0.0
k = 0.0
while True:
x = input("Enter your number here: ")
if (x == " "): # Check for a blank line entry here before attempting to convert to float
print("Average is:", (total/k))
break
x = float(x)
total = total + float(x)
k = k + 1
As noted in the comments, one should check for the blank line entry prior to attempting to convert the entry.
You are immediately casting the value of x that is inputted to a float. So,
if type(x) != int
always is true, meaning the loop breaks after one iteration every time.
Others have already solved your problem in different ways, but I think that explaining our thinking might also be useful.
Currently, your program is not checking correclty the exit condition (empty line is entered instead of a number). When a new line is entered, your program should do one of the two possible scenarios:
when an empty line is entered: print result & exit (break)
else (assume a number is entered): add number to total
No third option is specified, so for now, let's assume that every line will either be an empty line or a number. Will expand it later.
After you decided what to do, the actions should just be easily wrapped in a while True: block - so it should be:
initialize_variables_total_and_count
while True:
read_line
decide_what_to_do:
# in case line was a number
convert_line_to_float
add_float_to_total
increment_count
other_case:
# empty line was entered
calculate_and_print
break
With only two options, you only need to decide once what to do. You can swap around the cases by deciding which condition to check for (and that also results in the other being the "default" behavior for other cases).
It's simpler to check for the line being empty with if line_entered == "":. In this case, any non-empty line is treated like a number, and if it were not one, the float() function will error out and your program crashes.
Checking if a string (the entered line) can be converted to a float is a bit harder. There is just no built-in for that in python, but there is a trick: you can try to convert it to a float, and if that works, it was convertible, and if that errors, it was not. There are other ways too, but this is the simplest - see this question on the topic.
In this case, every number will be added to the total, and every non-number (including the empty line, but also random strings like "asdf") will cause the program to calculate the total and stop.
You can avoid putting both cases into an if-else block by using break or continue. (technicly, you never need to use break or continue, all programs can be written without them. In this case, you could have a boolean variable, named run for example, write while run: and instead of break, do run = False). You can use the fact that both break and continue end the loop early to avoid placing the second case inside an else-block and still have the same behavior (as break and continue already causes skipping the rest of the loop body).
So an example implementation: (testing for == "", not using unstructured control flow)
total = 0
count = 0
run = True
while run:
line = input("Enter your number here: ")
if line == "":
print(total / count)
run = False
else:
total += float(line)
count += 1
I also renamed k to count, x to line and used in-place addition operators.
Another implementation, with break, testing for float with try/except (and re-using that for the entire control flow):
total = 0
count = 0
while True:
line = input("Enter your number here: ")
try:
# order matters here. If the first line errors out, the second won't happen so the count will only be inremented if it was indeed a float
total += float(line)
count += 1
except:
print(f"Average is: {total / count}")
break
Here I removed the run variable, and used a format string to print a bit fancier.
And an example using both continue and break:
total = 0
count = 0
while True:
line = input("Enter your number here: ")
if line != "":
total += float(line)
count += 1
continue
print(f"Average is: {total / count}")
break
You can fancy it a bit with adding more error handling - use three cases:
user entered empty line: print & exit
user entered a number: add to total
user entered something else: ignore line, but tell user what to do
I only provide one example implementation for this, but as you can see, it can be implemented in many ways.
total = 0
count = 0
# good practice to tell the user what to do
print("Average calcuator. Enter numbers one per line to calulate average of, enter empty line to print result & exit!")
while True:
line = input("Enter your number here: ")
if line == "":
print(f"Average is: {total / count}")
break
else:
try:
total += float(line)
count += 1
except ValueError:
print("You should enter a number or an empty line to calculate & exit!")

Tips for completing this python task

I'm very new to coding and python and would like some help with finishing this small assignment I've been given.
The requirements of the project are as follows:
Create a Python application that will loop between 1 and 100
The numbers are to be printed out alongside their squared value
The app should stop when a squared value of 200 or more is reached
Reconfigure the application to take in a user value to produce squared values up to
Currently I can create the first two points, and have some idea with allowing user input into the app. With the below being the coding.
# The program to find the square of all numbers present in the list
# variable to store the squared numbers
square = 1
x = 200
# List of numbers
numbers = range(1,100)
#iterate over the list
for val in numbers:
square = val*val
# prints the output
print ("The square of ", val, "is", square)
Since your question says program stops when a square value of 200 or more is reached, I'll provide my implementation:
#square = 1 You can comment out this line since this is redundant.
#x = 200 Even this line is redundant.
# List of numbers
numbers = range(1,100)
#iterate over the list
for val in numbers:
square = val*val
if square >= 200:
exit() #I prefer exit() statement over break statement, you can decide what would suit better for you
print ("The square of ", val, "is", square)
You need to provide an upper limit for the square. I assume the user input will be the upper limit for the squares. I would code it like this:
n = int(input())
i = 1
while (i*i<n):
print(i, i*i)
i+=1

Riemann sum python

I need to make a python function where i can find the surface with the riemann sum. This is what i have , and with the feedback of my teacher i am very close to it, but it does not work as properly as i want. the teacher said also something about try-catch what means that i need to make an extra code to control the answer (if im not wrong) To find the surface the uppper and the lower limits are asked and how many rectangles you want under the line like in the program.
(edit) I have made a new program , could you guys check if this is correct.
import math
def f(x): return math.sqrt(x) #Function in the left!
a = int(input("What is the lowerlimit?:"))
b = int(input("What is the upperlimit?:"))
n = int(input("How many division intervals do you want?:"))
dx = (b-a)/n;
xi = 0;
sum = 0;
for i in range(n):
xi = xi+dx;
sum = sum + f(xi)
print("The surface under the line is ", (sum*dx))
#einde programma!
import math
def f(x):
return math.sqrt(x) #Function in the left!
def positiveinput(message):
while True:
try:
c = int(input(message))
if c <= 0:
raise ValueError
break
except ValueError:
print("Oops! That was no valid number. Try again...")
a = positiveinput("What is the lowerlimit?: ")
b = positiveinput("What is the upperlimit?: ")
c = positiveinput("How many division intervals do you want?: ")
a = int(input("What is the lowerlimit?:"))
b = int(input("What is the upperlimit?:"))
c = int(input("How many division intervals do you want?:"))
dx = float((b-a)/c)
xi = a
Sum = dx
for i in range(0,c):
xi = a - dx
Sum = Sum + f(xi)
print("The surface under the line is ", (sum*dx))
There are a few issues with the code above:
1) Most importantly, You don't actually calculate the correct answer because you are assuming that the lower limit is equal to 0. Instead of writing xi=0 you should be writing xi=a!!! (Note that this will use the far end of each rectangle to calculate the height - if you want to use the lower end, and don't want to change any other code you will need to write xi = a - dx so you start on a. (Having said that, I wouldn't do it this way, but this is how to fix this without changing anything else).
2) Validation errors: There are a few things you should check:
That the values of a, b are valid numbers (note they shouldn't really have to be integers, just numbers). You can use float() to convert something to a number, just as you would use int() to convert to an integer.
that n is an integer and is not equal to 0, as that will raise an error, when you try and divide by n,
that n is not negative, as this will result in you getting the wrong value (with the code as it is).
Having said that, I would not write the code as it is. Using a for-loop and then incrementing your value is not a very pythonic thing to do. You might be interested to learn you can actually specify a lower bound and an upper bound using the range function. Experiment with:
for i in range(3,11,0.5):
print(i)
See what happens. I'm not going to give you a full solution, as this is a homework assignment, and it will benefit you most to work it out yourself, but hopefully this points you these things will point you in the right direction.
As #Sadap said, you can try something like this:
def positiveinput(message):
while True:
try:
n = int(input(message))
if n <= 0:
raise ValueError
break
except ValueError:
print("Oops! That was no valid number. Try again...")
a = positiveinput("What is the lowerlimit?:")
b = positiveinput("What is the upperlimit?:")
n = positiveinput("How many division intervals do you want?:")
Having this code as a guide, you can complete the list of errors verification that #tim-mccurrach have written in an answer to this post. Also you can check out this link where they make the Riemann Sum in a different way. For documentation about try-catch you can enter this link.

How can this random python behaviour be explained?

This small script generates a random float beween 0 and 1 and then if its less than "0.000111111111111" it will print the message "found it"
import random
value = 0.4 / 3600
print value
while True:
rand = random.random()
print "RAND IS: " + str(rand) + "----- VAL IS " + str(value)
if rand < value:
print "found it"
So seemingly the script runs and it never actually "finds it", however when I comment out the print statement before the if statement the command line is FILLED with "found it" even though the rand value isn't less than value. What the hell?
Your while loop is designed to run forever as True is always True. You never break out of that infinite loop. Even if it finds the value, it just prints it because the condition you give to the while loop is still True. Since you cannot change the condition, you need to add a break statement:
while True:
rand = random.random()
print "RAND IS: " + str(rand) + "----- VAL IS " + str(value)
if rand < value:
print "found it"
break
Your program does find numbers that are both smaller and larger than 'value', whether or not it prints all of them out. It's just that the output, both ways, is confusing you. This is because: (a) your computer is faster than you can probably imagine, as long as it doesn't have to print anything; (b) but when it does have to print something it slows down to the point where you can actually see the printouts go by; (c) the number of iterations in between successful "findings" is bigger than you may have expected.
To demonstrate all of the above, I wrote this script:
#! /usr/bin/python
import time
import random
import csv
import sys
def how_long_until(v):
n = 0
start = time.clock()
rng = random.random
while True:
n += 1
if rng() < v: break
stop = time.clock()
return n, stop - start
wr = csv.writer(sys.stdout, quoting=csv.QUOTE_MINIMAL)
wr.writerow(("loops", "cpu.time"))
value = 0.4 / 3600
for _ in range(10000):
wr.writerow(how_long_until(value))
This generates random numbers until it finds one less than your "value", and then it writes out the number of loop iterations and the elapsed CPU time to find it. It does this TEN THOUSAND TIMES. On my computer, which is old but not that old, this program took six seconds to run.
And then I plotted histograms of both. First, let's look at the number of loops:
You can see that, although it often takes only a few thousand iterations to find a random number smaller than 0.4/3600, it can take as many as 80,000 iterations! This is why it might have seemed to you that "found it" was never being printed.
Now let's look at elapsed time:
It looks very similar to the histogram of the number of loops, but notice the X-axis scale. That's time in milliseconds. Even when it takes 80,000 iterations to find the next number smaller than 0.4/3600, it only takes the computer four milliseconds to accomplish that feat! This is why it seemed to you that "found it" was continuously getting printed when you commented out the per-iteration printout.

Python for loop with adding to an equation?

I need some help in this program. I need help figuring out how to make it calculate interest for a period over ten years (including the first one). This is as far as i have gotten on my own. I would greatly appreciate some insight to this problem.
Thanks.
*The "print() is just for spacing so that the program looks cleaner.
p= int(input(" Intial Amount? "))
print()
r= float(input(" Rate? (Decimal) "))
print()
n= int(input(" Number Of Times Compunded? (Yearly) "))
print()
t= float(input(" Number Of Years? "))
A= p*(1+r/n)**(n*t)
print()
print( " Interest At Final Year","$",format(A, ',.2f'))
print()
for i in range (10):
print(format(i+1, '3')," Year","Interest","$",format(A,',.2f'))
In the body of your loop, you are not updating the values of any of the variables. You need to update A at every iteration or store the intermediate results in some other variable. As an example, see the following:
def compound_interest(r, n, initial):
current_value = initial
for i in range(n):
current_value *= (1 + r)
print(current_value)
I use the current_value variable to save the intermediate results of the loop. If I had simply done initial * (1 + r) at every iteration then the value of initial would never change; the result of the calculation must be saved if you want to keep using it.
At the very end of the program it will count 1-10 but it will have the same amount as the first calculation.
Yes, that's because the only thing that happens in that loop is the print call. You're just calculating A all at once, before you get into the loop, and then using the same A over and over again.
I need help making it add the new values to add up while the "n" and the "p" are changing.
Well, you aren't changing n or p, and I don't think you need to. But you do need to change something. If you want to print a different value of A each time through the loop, you have to recalculate next year's A based on the previous year's A, or whatever else goes into determining the right value.
For example:
for year in range (10):
jan1balance = p
for period in range(n):
p = p * (1 + r)
print(format(year+1, '3')," Year","Interest","$",format(p - jan1balance,',.2f'))
Or:
for year in range (10):
yearlyinterest = 0
for period in range(n):
periodinterest = p * r
yearlyinterest += periodinterest
p += periodinterest
print(format(year+1, '3')," Year","Interest","$",format(yearlyinterest,',.2f'))

Categories