Having trouble getting this code to work. Only ever prints 0.0. I'm a complete beginner to python and I'm aware that I've probably made a very simple mistake, and that my code is poorly written.
import math
import random as ran
import numpy as np
nodarts=1000
nhits = 0
def isInTheCircle(nhits,nodarts):
for i in range(nodarts):
x = ran.uniform(-1,1)
y = ran.uniform(-1,1)
if np.sqrt(x*x + y*y) >= 1:
nhits += 1
isInTheCircle(nhits,nodarts)
pi = (4.0*nhits)/(nodarts)
print(pi)
The value of nhits never changes from zero.
You have a function defined (isInTheCircle) and you call this function, but it does not return anything. You need to rewrite it to return nhits and assign this value to a variable (presumably also called nhits).
def isInTheCircle(nhits,nodarts):
for i in range(nodarts):
x = ran.uniform(-1,1)
y = ran.uniform(-1,1)
if np.sqrt(x*x + y*y) <= 1:
nhits += 1
return nhits
nhits = isInTheCircle(nhits,nodarts)
pi = (4.0*nhits)/(nodarts)
print(pi)
What may be confusing you is the "scope" of the variable nhits. Basically, just because you have a variable named nhits inside and outside the function does NOT make them the same variable. The variable inside the function changes, but the variable outside the function does not necessarily change (it does sometimes depending on type....but that's another story). Read up on "variable scope in python" to better understand this.
Related
I wrote a script in Python that finds the zero of a fairly complicated function using fsolve. The way it works is as follows. There is a class that simply stores the parameter of the function. The class has an evaluate method that returns a value based on the stored parameter and another method (inversion) that finds the parameter at which the function takes the supplied output.
The inversion method updates the parameter of the function at each iteration and it keeps on doing so until the mismatch between the value returned by the evaluate method and the supplied value is zero.
The issue that I am having is that while the value returned by the inversion method is correct, the parameter, that is part of the object, is always 0 after the inversion method terminates. Oddly enough, this issue disappears if I use root instead of fsolve. As far as I know, fsolve is just a wrapper for root with some settings on the solver algorithm and some other things enforced.
Is this a known problem with fsolve or am I doing something dumb here? The script below demonstrates the issue I am having on the sine function.
from scipy.optimize import fsolve, root
from math import sin, pi
class invertSin(object):
def __init__(self,x):
self.x = x
def evaluate(self):
return sin(self.x)
def arcsin_fsolve(self,y):
def errorfunc(xnew):
self.x = xnew
return self.evaluate() - y
soln = fsolve(errorfunc, 0.1)
return soln
def arcsin_root(self,y):
def errorfunc(xnew):
self.x = xnew
return self.evaluate() - y
soln = root(errorfunc, 0.1, method = 'anderson')
return soln
myobject = invertSin(pi/2)
x0 = myobject.arcsin_fsolve(0.5) #find x s.t. sin(x) = 0.5 using fsolve
print(x0) #this prints pi/6
x0obj = myobject.x
print(x0obj) #this always prints 0 no matter which function I invert
myobject2 = invertSin(pi/2)
x1 = myobject2.arcsin_root(0.5) #find x s.t. sin(x) = 0.5 using root
print(x1) #this prints pi/6
x1obj = myobject2.x
print(x1obj) #this prints pi/6
If you add print statements for xnew in the errorfunc then you will see that fsolve works with a list (of one element). This means that the function is re-interpreted that way, not the original function. Somehow the type information is lost after exiting the solver so that then the address/reference to that list is interpreted as floating point data, which gives the wrong value.
Setting self.x = xnew[0] there restores the desired behavior.
I am having a problem.
def f(x):
function = input("Enter yoru Function: ")
return function
a = -1
b = 2
a_Applied = f(a)
b_Applied = f(b)
if a_Applied < 0 and b_Applied > 0:
print "IVT Applies."
elif a_Applied > 0 and b_Applied < 0:
print "IVT Applies"
else:
print "IVT Does Not Apply"
This is my current code. I am trying to let the user make a function in line 2. However this breaks the program because it is a string. How do I get it to not be a string, and instead for it to be able to take a function.
Ex.
User inputs "2*x + 1"
In a perfect world the program then runs 2(a) +1 and 2(b) + 1 and then compares them using the if statement. Because the input is a string ti doesn't work.
Any help?
Use lambda expression and eval function. Like this.
def read_user_function():
function_str = input("Enter your Function: ")
return lambda x: eval(function_str, { 'x' : x })
Call user function by
f = read_user_function()
print(f(2))
Here is a demo https://repl.it/ITuU/2.
Explanation
The function above, read_user_function returns a lambda expression, basically a function, that will evaluate the user's input with the variable, sort of like a parameter, x set to the x value that is passed to the lambda expression. This can get confusing if your new to this sort of thing but just think of read_user_function as returning an anonymous function that accepts a single argument and its body equals eval(function_str, { 'x' : x })
Warning
This is a quick and dirty solution to evaluating mathematical expression. The function would execute any valid python code and not only mathematical expression. This may be dangerous if your application is sensitive - you wouldn't want the user executing custom code.
What you're asking to do is very hard (in general). You'd need to define rigorous semantics for all your supported operations (for example, is power ^ or is it ** like you'd do in python?).
The sympy library has a start on this for you. If you assume your input is a polynomial, for example:
import sympy
y = sympy.Poly("x^2 + 2*x + 1")
print(y(3))
# outputs 16
sympy also has the advantage that it will accept "python-like" input as well:
import sympy
y = sympy.Poly("x**2 + 2*x + 1")
print(y(3))
Note that sympy is not limited to polynomials, just included them here as an example because polynomials are relatively simple.
I'm using python 3.5.
So I'm trying to create a function that takes x and y as positive float input, and then computes and returns R = x - N * y, where N is the largest integer, so that x > N * y.
I made this function:
def floatme(x,y):
N = 1
while x <= N * y:
R = x - N * y
N = N+1
return R
but then I receive the following error, when running my function:
UnboundLocalError: local variable 'R' referenced before assignment
I searched around and found that this happens when an assigned variable in the function, is already assigned outside of it. But this is not the case for my function, so I do not understand why Python is complaining?
R is defined inside the while loop. If the condition of the while loop is not true initially, its body never executes and R is never defined. Then it is an error to try to return R.
To solve the problem, initialize R to something before entering the loop.
If not entering the loop is an error condition, i.e. the caller should not be passing in values that cause the problem to begin with, then catch the UnboundLocalError using a try/except structure and raise a more appropriate exception (such as ValueError).
I'm afraid your code has an infinite loop with while x <= N * y: . Value of x will never increase in the code. (perhaps you meant to use >= instead?)
That being said, you will still get UnboundLocalError even if you define R outside. You have to tell the function that it's global.
R = None # init
def floatme(x,y):
global R # THIS IS THE KEY LINE
N = 1
while x >= N * y: # changed to >=
R = x - N * y
N = N+1
return R
At this point it's worth noting that this function is just doing x % y if x>=y else None so I'm not sure if I get the intent here.
I think my question should be more clearly understood by this short code:
fs = []
for k in range(0, 10):
def f(x):
return x + 2*k
fs.append(f)
fs[0](1)
# expecting 1 but 19(=1+2*9)
How do I instead make f return what I want? Please note that f cannot receive k as an argument.
(What I'm actually trying to do is prepare multiple constraint functions that are fed to scipy.optimize.minimize)
The typical way to fix this is to do something like:
def f(x, k=k):
return x + 2*k
For the most part, this shouldn't affect your "f cannot receive k as an argument" condition because it isn't a required argument.
A related, but different approach would be to define f out of the loop.
def f(k, x):
return x + 2*k
Then in the loop use functools.partial.
import functools
fs = []
for k in range(10):
fs.append(functools.partial(f, k))
In this approach, your function won't accept a value for k even if you try to pass one.
Basically the problem is that the variable k, in this case, continually changes as the loop iterates. This means that all things which are pointing to the variable "k" are pointing to the same value at all times.
There are a couple of ways to solve this. This is perhaps the most common.
def f(x, k=k):
# This sets k as a locally bound variable which is evaluated
# at the time the function is created.
return x + 2*k
The detriment is that this solution will allow a later function to call the newly created functions with a different value of k. This means you could call f("cat","dog") and get "catdogdog" as a return. While this is not the end of the world, it certainly isn't intended.
However, you could also do something like this:
def f_maker(k):
# Create a new function whose variable "k" does not exist in outside scope.
def f(x):
return x + 2*k
return f
fs = []
for k in range(0, 10):
fs.append(f_maker(k))
fs[0](1)
This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 9 years ago.
I am python beginner and at the moment I am struggling with python recursion function:
x = 10
n = 3
def rec(x,n):
if n>0:
#global x2
x2 = x*n
return rec(x2,n-1)
else:
return x2
# function call:
fcall = rec(x,n)
print fcall
What confuses me is that global x2 line. With it, the function is working fine returns 60 as expected, but without it I am getting an error message:
Local variable 'x2' referenced before assignment
Why is that so?
Seems like once n reaches value of 3, and the else condition gets executed, it does not know what x2 is?
If you leave out the global, then the variable is expected to be in local scope within that function. That means that it needs to be assigned somewhere to actually exist. As the only assignment is when the n > 0 condition is true, the return x2 will always try to return a variable that does not exist.
When you add the global, you put that variable into the global scope, making it available everywhere. So it’s assigned and can be returned.
However, it’s not really a good idea to have a function depend on a global variable like that. It seems very unobvious that a global variable is required for it to work. And in fact, it’s not necessary here: Instead of x2 you want to reference x.
def rec (x, n):
if n > 0:
x = x * n
return rec(x, n - 1)
else:
return x
That way, as long as n is still bigger than zero, you multiply the current x by n and temporarily assign it to x again, which you then pass to the recursive call. If n is equal to zero, then the else case applies, and you just return the current x that was passed to the function.
Your problem is that x2 is only a local variable, so when you call the function it doesn't know the old x2 anymore.
By adding the global x2 you put that variable in the global space, so now the function can recognise it.
Check this out: http://gettingstartedwithpython.blogspot.de/2012/05/variable-scope.html
What you actually want to return is x, not x2, because you are passing the value of x2 into the next call of your recursion.
def rec(x,n):
if n>0:
x2 = x*n
return rec(x2,n-1)
else:
return x
Without global x2, assigning to x2 creates a new local variable. With it, assigning to x2 makes it change the global x2 variable. This applies only to assignment, not to looking up variables.
The current stack frame (and thus all local variables associated with it) disappears when the function returns, but globals stay forever and ever and ever (and you should also feel very bad for using them).
And also you can refactor your rec function code to:
def rec(x, n):
return rec(x*n, n-1) if n else x
A typical cause of problems for beginning programmers is the habit of using too many variables. This can make things more complicated and harder to understand. Your code can be made simpler like this:
def rec(x, n):
if n > 0:
return rec(x*n, n-1)
return x
or even this, using the ternary operator:
def rec(x, n):
return rec(x*n, n-1) if n > 0 else x
You can then try it out by just doing:
rec(3, 10)
The sooner you can build a habit creating new variables only when they are needed or improve the readability of the code, the easier your programs will be to write, debug and read.