Python gives strange values of factorial - python

x = 5
def SsolGom():
k = 1
for i in range( 1 , x+1 ):
k = k * i
print(SsolGom)
=function SsolGom at 0x00F1B660
120 must come out but strange value came out...

SsolGom is a function, SsolGom() is the value returned by this function. It's similar in math: sin is a function, sin(0) is a number.
x = 5
def SsolGom():
k = 1
for i in range( 1 , x+1 ):
k = k * i
return k
print(SsolGom())
# 120
You need to have a correct indentation inside your function, and you need to return a value. SsolGom() would be None otherwise.
Note that x probably shouldn't be a global variable. Otherwise, your function could be replaced by return 120:
def factorial(x):
k = 1
for i in range(x):
k = k * (i + 1)
return k
print(factorial(5))
Finally, here's the easiest way to get factorial in Python:
>>> from math import factorial
>>> factorial(5)
120

You're missing the brackets. It should be:
print(SsolGom())

You are printing the function without the parenthesis. Calling a function with and without parenthesis gives different results in Python. If you do not provide a parenthesis, Python considers it as properties and not a method/function. Hence you got that result
provide a return statement in the function.
Updated Code:
x=5
def SsolGom():
k=1
for i in range( 1 , x+1 ):
k=k*i
return k
print(SsolGom())

Related

How to pass a function as an argument

I would like to find an approximate value for the number pi = 3.14.. by using the Newton method. In order to use it also for some other purpose and thus other function than sin(x), the aim is to implement a generic function that will be passed over as an argument. I have an issue in passing a function as an argument into an other function. I also tried lambda in different variations. The code I am showing below produces the error message: IndexError: list index out of range. I will appreciate your help in solving this issue and eventually make any suggestion in the code which may not be correct. Thanks.
from sympy import *
import numpy as np
import math
x = Symbol('x')
# find the derivative of f
def deriv(f,x):
h = 1e-5
return (lambda x: (f(x+h)-f(x))/h)
def newton(x0,f,err):
A = [x0]
n = 1
while abs(A[n]-A[n-1])<=err:
if n == 1:
y = lambda x0: (math.f(x0))
b = x0-y(x0)/(deriv(y,x0))
A.append(b)
n += 1
else:
k = len(A)
xk = A[k]
y = lambda xk: (math.f(xk))
b = newton(A[k],y,err)-y(newton(A[k],y,err))/deriv(y,k)
A.append(b)
n += 1
return A, A[-1]
print(newton(3,math.sin(3),0.000001))
I don't know why you use sympy because I made it without Symbol
At the beginning you have to calculate second value and append it to list A and later you can calculate abs(A[n]-A[n-1]) (or the same without n: abs(A[-1] - A[-2])) because it needs two values from this list.
Other problem is that it has to check > instead of <=.
If you want to send function sin(x) then you have to use math.sin without () and arguments.
If you want to send function sin(3*x) then you would have to use lambda x: math.sin(3*x)
import math
def deriv(f, x, h=1e-5):
return (f(x+h) - f(x)) / h
def newton(x0, f, err):
A = [x0]
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
while abs(A[-1] - A[-2]) > err: # it has to be `>` instead of `<=`
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
return A, A[-1]
# sin(x)
print(newton(3, math.sin, 0.000001)) # it needs function's name without `()`
# sin(3*x)
print(newton(3, lambda x:math.sin(3*x), 0.000001))
# sin(3*x) # the same without `lambda`
def function(x):
return math.sin(3*x)
print(newton(3, function, 0.000001))
Result:
([3, 3.1425464414785056, 3.1415926532960112, 3.141592653589793], 3.141592653589793)
([3, 3.150770863559604, 3.1415903295877707, 3.1415926535897936, 3.141592653589793], 3.141592653589793)
EDIT:
You may write loop in newton in different way and it will need <=
def newton(x0, f, err):
A = [x0]
while True:
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
if abs(A[-1] - A[-2]) <= err:
break
return A, A[-1]

Loop a function using the previous output as input

When my function foo generating a new element, I want to reuse the output and put it in foo n-times. How can I do it?
My function:
def foo(x):
return x + 3
print(foo(1))
>>>4
For now. I'm using this method:
print(foo(foo(foo(1))))
There are a couple ways to do what you want. First is recursion, but this involves changing foo() a bit, like so:
def foo(x, depth):
if depth <= 0:
return x
return foo(x+3, depth-1)
and you'd call it like foo(1, n)
The other way is with a loop and temp variable, like so
val = 1
for _ in range(0, n):
val = foo(val)
Use a loop for this:
value = 1
for i in range(10):
value = foo(value)
def foo(x,y):
for i in range(y):
x = x + 3
return x
print (foo(10,3))
Output:
19
What you are searching for is called recursion:
def foo(x, n=1):
if n == 0:
return x
return foo(x + 3, n - 1)
Another possible with lambda and reduce
Reduce function
from functools import reduce
def foo(x):
return x + 3
print(reduce(lambda y, _: foo(y), range(3), 1))
You will get 10 as result
# y = assigned return value of foo.
# _ = is the list of numbers from range(3) for reduce to work
# 3 = n times
# 1 = param for x in foo

I can't decrement N, but I can use it when evaluating logic. Can someone explain this?

Increment is defined as:
def increment(x):
return x + 1
The following works, and spits out a result of 8:
def repeated(f, n):
def h(x):
counter = 0
while counter < n:
x = f(x)
counter += 1
return x
return h
addthree = repeated(increment,3)
addthree(5)
The following code errors and tells me that i am referencing n before assignment:
def repeated3(f,n):
def h(x):
total=0
while n != 0:
total = f(x) + total
n -= 1
return total
return h
addthree = repeated(increment,3)
addthree(5)
why does the error throw when i try to decrement n, even though i am allowed to use it in the logic statement that precedes it?
When functions are nested, the use of an argument or variable of an outer function in an inner function is called a closure.
Python closures are read only
So, if you want to use a decrement loop, you will need to copy the repetition argument to a writable local variable.
In [10]: def r(f,n):
....: def h(x):
....: total = 0
....: m = n
....: while m!=0:
....: total += f(x)
....: m -= 1
....: return total
....: return h
....:
In [11]: r(increment, 3)(0)
Out[11]: 3
This isn't a problem with the previously posted incrementing repeated() function code because although there the repetitions argument n is also a closure, it is used read-only in a comparison and not written to.
The first function works as you are not assigning/mutating n to a new value, using n -= 1 you are assigning n to a new value so you are creating a local variable n not using the n from the outer function so you end up with a local variable 'n' referenced before assignment error as n is not defined when you use while n != 0: in the local scope.
In python3, you can use the nonlocal keyword:
def repeated3(f, n):
def h(x):
nonlocal n
total = 0
while n != 0:
total = f(x) + total
n -= 1
return total
return h
If you are using python2 you could reassign a new variable to point to n and use that or use a dict:
def repeated3(f,n):
n = {"n":n}
def h(x):
total = 0
while n["n"] != 0:
total = f(x) + total
n["n"] -= 1
return total
return h
addthree = repeated3(increment,3)
addthree(5)
You could also make it a function attribute:
def repeated3(f,n):
repeated3.n = n
def h(x):
total = 0
while repeated3.n != 0:
total = f(x) + total
repeated3.n -= 1
return total
return h
addthree = repeated3(increment,3)
There are numerous other workarounds but the main point is you can read but not mutate the closure variable and creating n in your local scope is going to cause n to become a local variable meaning the while n != 0 is looking for n in the local scope so you get the referencing n before assignment:
You need to pass 'n' into h(x), making it local. So you have h(x,n=n).

Project Euler #15 in Python

I am newbie in Python. I'm stuck on doing Problem 15 in Project-Euler in reasonable time. The problem in memoize func. Without memoize all working good, but only for small grids. I've tried to use Memoization, but result of such code is "1" for All grids.
def memoize(f): #memoization
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
#memoize
def search(node):
global route
if node[0] >= k and node[1] >= k:
route += 1
return route
else:
if node[0] < k + 1 and node[1] < k + 1:
search((node[0] + 1, node[1]))
search((node[0], node[1] + 1))
return route
k = 2 #grid size
route = 0
print(search((0, 0)))
If commenting out code to disable memoize func:
##memoize
all works, but to slow for big grids. What am i doing wrong? Help to debbug. Thx a lot!
Update1:
Thank for your help, I've found answer too:
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
#memoize
def search(node):
n = 0
if node[0] == k and node[1] == k:
return 1
if node[0] < k+1 and node[1] < k+1:
n += search((node[0] + 1, node[1]))
n += search((node[0], node[1] + 1))
return n
k = 20
print(search((0, 0)))
Problem was not in memoize func as i thought before. Problem was in 'search' function. Whithout globals it wroiking right i wished. Thx for comments, they was really usefull.
Your memoization function is fine, at least for this problem. For the more general case, I'd use this:
def memoize(f):
f.cache = {} # - one cache for each function
def _f(*args, **kwargs): # - works with arbitrary arguments
if args not in f.cache: # as long as those are hashable
f.cache[args] = f(*args, **kwargs)
return f.cache[args]
return _f
The actual problem -- as pointed out by Kevin in the comments -- is that memoization only works if the function does not work via side effects. While your function does return the result, you do not use this in the recursive calculation, but just rely on incrementing the global counter variable. When you get an earlier result via memoization, that counter is not increased any further, and you do not use the returned value, either.
Change your function to sum up the results of the recursive calls, then it will work.
You can also simplify your code somewhat. Particularly, the if check before the recursive call is not necessary, since you check for >= k anyway, but then you should check whether the x component or the y component is >= k, not both; once either has hit k, there's just one more route to the goal. Also, you could try to count down to 0 instead of up to k so the code does not need k anymore.
#memoize
def search(node):
x, y = node
if x <= 0 or y <= 0:
return 1
return search((x - 1, y)) + search((x, y - 1))
print(search((20, 20)))
Try this code. It works fast even with grids over 1000x1000! Not nessesarily square.
But I didn't know about memoization yet...
import time
def e15():
x=int(input("Enter X of grid: "))
y=int(input("Enter Y of grid: "))
start = time.time()
lst=list(range(1,x+2))
while lst[1]!=y+1:
i=0
for n in lst[1:]:
i+=1
lst[i]=n+lst[i-1]
print(f"There are {lst[-1]} routes in {x}x{y} grid!")
end = time.time() - start
print("Runtime =", end)
e15()
This problem can be solved in O(1) time by using the code below:
from math import factorial as f
n, m = map(int, input("Enter dimensions (separate by space)?").split())
print ("Routes through a", n, "x", m, "grid", f(n+m) // f(n) // f(m))
Here's a link for a proof of the equation:
Project Euler Problem 15 Solution

Python programming beginner difficulties

I am trying to write a program in Python, but I am stuck in this piece of code:
def function():
a=[3,4,5,2,4]
b=1
c=0
for x in range(5):
if a[x-1]>b:
c=c+1
return c
print(function())
It gives me value 1 instead of 5. Actually the function I am trying to write is a little bit more complicated, but the problem is actually the same, it doesn't give me the right result.
def result():
r=[0]*len(y)
a=2
b=an_integer
while b>0:
for x in range(len(y)) :
if y[x-1] > 1/a and b>0:
r[x-1]=r[x-1]+1
b=b-1
a=a+1
return r
print(result())
v is a list of values smaller than 1 and b has an integer as value. If some values x in v are bigger than 1/a then the values x in r should get 1 bigger, then it should repeat a=a+1 until b becomes 0. I want this function to give a result of the type for ex. [7,6,5,4,3] where the sum of the elements in this list is equal to b.
Sometimes it gives me the right value, sometimes not and when the elements in v are equal for example v=[0.33333,0.33333,0.33333] it gets stuck and doesn't give me a result.
I don't know what I am doing wrong !
Your return statements are incorrectly indented. You want to return after the loop ends, not inside the loop.
def function():
a = [3, 4, 5, 2, 4]
b = 1
c = 0
for x in range(5):
if a[x-1] > b:
c = c + 1
return c
Also, a couple of optimizations to the code:
def function(a, b):
c = 0
for x in a:
if x > b:
c += 1
return c
or further:
def function(a, b):
return sum(x > b for x in a)
return; only inside the fun in the end it.
and name the Variable v

Categories

Resources