Recursive Function of factorial - python-3.x

I can't understand logic of the last line of the below mentioned code. The code is a recursive function that gives you Factorial of a number. What does this(factorial(n-1))return each time?
def factorial(n): if n<=1: return 1 else: return n*factorial(n-1)
=================================================================

If you're calculating the factorial of something you are doing
1 * 2 * ... * n
Another way of representing this is
n * (n-1) * (n-2) * ... * 1
Or more simplified
n * (n-1) * ((n-1)-1) * ... * 1
Looking at that last bit you should be able to see that if the number is 1 the answer is 1. Otherwise it's the a number n times whatever the result of the factorial of (n-1) is.
That's exactly what this function does.
def factorial(n): # declare the function
if n<=1:
return 1 # if n is 1 or lower, the answer should be 1.
else:
# otherwise, the answer is the result of n * (all these steps again for (n-1))
return n*factorial(n-1)
Say you give factorial(5) what actually happens is
factorial(5) = 5 * factorial(4)
= 5 * (4 * factorial(3))
= 5 * (4 * (3 * factorial(2)))
= 5 * (4 * (3 * (2 * factorial(1))))
= 5 * (4 * (3 * (2 * 1)))

Related

Python Truth value of a series is ambiguous error in Function

I 'm trying to build a function that uses several scalar values as inputs and one series or array also as an input.
The function applies calculations to each value in the series. It works fine so far. But now I'm adding a phase where it has to check the value of the series and if it's less than X it performs one calculation other it performs a different calculation.
However I keep getting a 'truth value series is ambiguous error and I can't seem to solve it.
What is a work around?
My code is below
import numpy as np
import pandas as pd
import math
tramp = 2
Qo = 750
Qi = 1500
b = 1.2
Dei = 0.8
Df = 0.08
Qf = 1
tmax = 30
tper = 'm'
t = pd.Series(range(1,11))
def QHyp_Mod(Qi, b, Dei, Df, Qf, tmax, tper, t):
tper = 12
Qi = Qi * (365/12)
Qf = Qf * (365/12)
ai = (1 / b) * ((1 / (1 - Dei)) ** b - 1)
aim = ai / tper
ai_exp = -np.log(1 - Df)
aim_exp = ai_exp / tper
t_exp_sw = 118
Qi_exp = Qi / ((1 + aim * t_exp_sw * b) ** (1 / b))
Qcum = (Qi / (aim * (1 - b))) * (1 - (1 / ((1 + aim * t * b) ** ((1 - b) / b))))
t_exp = t - t_exp_sw
Qcum_Exp = (Qi_exp / aim_exp) * (1 - np.exp(-aim_exp * t_exp))
if t < t_exp_sw:
return Qcum
else:
return Qcum_exp
z = QHyp_Mod(Qi=Qi, b=b, Dei=Dei, Df=Df, Qf=Qf, tmax=tmax, tper=tper, t=t)
Replace the if - else statement:
if t < t_exp_sw:
return Qcum
else:
return Qcum_exp
with this:
Q.where(t < t_exp_sw, Q_exp)
return Q
The where method tests the conditional for each member of Q, if true keeps the original value, and if false replaces it with the corresponding element of Q_exp

Creating a large letter 'A' in python [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I started printing a pyramid to start...
Here's what I made so far:`
num = int(input("Enter the Number: "))
for i in range(1, num+1):
for j in range(0, i):
print(" ", end="")
for j in range(1, (num*2 - (2*i - 1))+1):
if i == 1 or j == 1 or j ==(num*2 -(2*i-1)):
print("*", end="")
else:
print(" ", end="")
print()
This is what the output should look like...
*
* *
* *
* *
*********
* *
* *
* *
Here a simple solution.
def large_a(height):
rows = ["*"] + ["*" + " " * (2 * i + 1) + "*" for i in range(height - 1)]
middle = len(rows) // 2
rows[middle] = rows[middle].replace(" ", "*")
return "\n".join(f"{r:^{height * 2}}" for r in rows)
print(large_a(8))
*
* *
* *
* *
*********
* *
* *
* *
print(large_a(15))
*
* *
* *
* *
* *
* *
* *
***************
* *
* *
* *
* *
* *
* *
* *

Code takes forever to come up with a solution

What I basically want, is comparing a timevalue (t1 and tuit)(in hours) to determine which method to use to calculate 'S' and 'k' in a function called 'stijghoogteverlaging'. Then a fitted curve can be made with those values.
I tried multiple things, like putting 'return s' underneath both s-methods.
if t1[i] < tuit:
s = Q / (4 * np.pi * k * D) * exp1(S * r**2 / (4 * k * D * t))
return s
else:
s = Q / (4 * np.pi * k * D) * ((exp1(S * r**2 / (4 * k * D * t))) - (exp1(S * r**2 / (4 * k * D * (t - tuit)))))
return s
But then I got a wrong fitted curve as can be seen in the image below.
Now I tried putting only one 'return s', but then it takes forever to calculate and I have to interrupt the kernel.
data = read_csv("pompproef_data.csv", sep = ';')
pb1 = data.iloc[1:,1].values-1.87
pb2 = data.iloc[1:,2].values-1.86
t1 = data.iloc[1:,0].values / (60*24)
volume = 10/1000 #m3
duur = [128,136, 150, 137, 143, 141] #seconden
totaal = np.sum(duur)
debiet = (((len(duur) * volume)/totaal)) * (60*60*24) #m3/d
print(debiet)
print(t1)
print(pb1)
tuit = 15/(24*60)
D = 2.0
Q = debiet
def stijghoogteverlaging(t, k, S):
for i in range(len(t1)):
if t1[i] < tuit:
s = Q / (4 * np.pi * k * D) * exp1(S * r**2 / (4 * k * D * t))
else:
s = Q / (4 * np.pi * k * D) * ((exp1(S * r**2 / (4 * k * D * t))) - (exp1(S * r**2 / (4 * k * D * (t - tuit)))))
return s
r = 4.0 #afstand peilbuis1 tot put
poptpb1, pcovpb1 = curve_fit(stijghoogteverlaging, t1, pb1, p0=[100, 1e-25], maxfev = 10000000)
print('optimale waarde van k voor peilbuis1:', poptpb1[0])
print('optimale waarde van S voor peilbuis1:', poptpb1[1])
tijd = data.iloc[1:,0].values
t = np.linspace(0.00069*(24*60), 0.021*(24*60), 1000)
s1 = stijghoogteverlaging(t, poptpb1[0], poptpb1[1])
plt.plot(tijd, pb1, 'r.', label = 'Gemeten bij 4 meter')
plt.plot(t, s1, 'b', label = 'fitted bij 4 m')
Does anyone have a solution?
Used values for t1 and pb1:
Plot with a wrong fitted curve(time in minutes).
The function stijghoogteverlaging is performing a nonsense operation over and over:
def stijghoogteverlaging(t, k, S):
for i in range(len(t1)):
if t1[i] < tuit:
s = Q / (4 * np.pi * k * D) * exp1(S * r**2 / (4 * k * D * t))
else:
s = Q / (4 * np.pi * k * D) * ((exp1(S * r**2 / (4 * k * D * t))) - (exp1(S * r**2 / (4 * k * D * (t - tuit)))))
return s
You are iterating len(t1) times, and at each iteration, you are computing the full vectorized value of s each and every time. That means that you are computing len(t)**2 values per call, and using a Python for loop as your outer loop to do it. As a minor point, you are accessing the x-data as the global variable t1 instead of the local value t, which gets passed in.
Your function should probably look more like this:
def stijghoogteverlaging(t, k, S):
return np.where(t < tuit,
Q / (4 * np.pi * k * D) * exp1(S * r**2 / (4 * k * D * t)),
Q / (4 * np.pi * k * D) * ((exp1(S * r**2 / (4 * k * D * t))) - (exp1(S * r**2 / (4 * k * D * (t - tuit)))))
)
This computes len(t) * 2 values per call, not len(t)**2, and selects a value from the appropriate result for each value of t.

Length of the factorial

I tried running the program below:
from functools import lru_cache
#lru_cache(Maxsize = None)
def count(n):
factorial_num = 1
num_digits = 0
if n == 1:
factorial_num = 1
else:
factorial_num = n * count(n-1)
return len(str(factorial_num))
However, it didn't give me the length of the factorial number as anticipated.
I also wanted to use the code to find the factorial of very big numbers in range of billions and tried using lru_cache. Still, no luck.
As Aziz pointed out in the comments, your recursive case is wrong.
factorial_num = n * count(n-1)
This would do something useful if count(n-1) actually returned (n-1)!, but it doesn't, since you're trying to return a digit count instead.
>>> count(1)
1 # Base case is correct.
>>> count(2)
1 # 2 * count(1) = 2 * 1 = 2. Whose *length* is 1 digit.
>>> count(9)
1 # For all single-digit n, count(n) is still 1.
>>> count(10)
2 # 10 * count(9) = 10 * 1 = 10. Whose *length* is 2 digits.
You should write a function that just calculates the factorial, instead of trying to mix this logic with the digit counting.
#lru_cache(maxsize=None)
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
Note that recent versions of Python have a built-in math.factorial function, which you could use instead if your teacher is not requiring you to roll your own factorial code.
Then, you can simply use len(str(factorial(n))) to count the digits.
You can use Kamenetsky formula to return the number of digits in n!
For minor numbers use:
def findDigits(n):
if (n < 0):
return 0;
if (n <= 1):
return 1;
digits = 0;
for i in range(2, n + 1):
digits += math.log10(i);
return math.floor(digits) + 1;
For bigger numbers use:
def findDigits(n):
if (n < 0):
return 0;
if (n <= 1):
return 1;
x = ((n * math.log10(n / math.e) +
math.log10(2 * math.pi * n) /2.0));
return math.floor(x) + 1;
source: https://www.geeksforgeeks.org/count-digits-factorial-set-1/?ref=lbp and https://www.geeksforgeeks.org/count-digits-factorial-set-2/?ref=lbp

How can I correctly implement this example of using classes?

In the following example, one can choose constants to depend upon the context of a future situtation.
class Constants:
SPEEDLIGHT = 3 * 10**8
GRAVITY = 9.81
C = Constants()
print(C.GRAVITY)
>> 9.81
That was not too difficult because each quantity is a fixed constant. But suppose I want to do something similar for functions. In this first block of code below, I specify two distributions of integrable variable x and fixed parameters a and b.
class IntegrableDistribution:
def Gaussian(x,a,b):
cnorm = 1 / ( b * (2 * pi)**(1/2) )
return cnorm * np.exp( (-1) * (x-a)**2 / (2 * b**2) )
# Gaussian = Gaussian(x,a,b)
def Lognormal(x,a,b):
cnorm = 1 / ( b * (2 * pi)**(1/2) )
return cnorm * exp( (-1) * (np.log(x)-a)**2 / (2 * b**2) ) / x
# Lognormal = Lognormal(x,a,b)
I was trying to name the distributions so that they could be callable. That resulted in an error message, hence the commented out code above. In this next block of code, I am trying to use an input to select a distribution for integration (though I feel it is extremely inefficient).
Integrable = IntegrableDistribution()
class CallIntegrableDistribution:
def Model():
def Pick():
"""
1 : Gaussian Distribution
2 : Lognormal Distribution
"""
self.cmnd = cmnd
cmnd = int(input("Pick a Distribution Model: "))
return cmnd
self.cmnd = cmnd
if cmnd == 1:
Distribution = Integrable.Gaussian
if cmnd == 2:
Distribution = Integrable.Lognormal
return Distribution
OR ALTERNATIVELY
cmnd = {
1: Gaussian,
2: Lognormal,
}
I'm not really concerned with the problem of distributions; I'm only applying it to showcase my knowns and unknowns. What are some ways to properly do this or something similar/simpler using classes or dictionaries?
Use static methods:
class IntegrableDistribution:
#staticmethod
def Gaussian(x,a,b):
cnorm = 1 / ( b * (2 * pi)**(1/2) )
return cnorm * np.exp( (-1) * (x-a)**2 / (2 * b**2) )
#staticmethod
def Lognormal(x,a,b):
cnorm = 1 / ( b * (2 * pi)**(1/2) )
return cnorm * exp( (-1) * (np.log(x)-a)**2 / (2 * b**2) ) / x
And usage:
some_result = IntegrableDistribution.Gaussian(1, 2, 3)
another_result = IntegrableDistribution.Lognormal(1, 2, 3)

Resources