Understanding factorials in Python - python

I know how to code a function for the factorial of a number but I am not sure why it works.
def factorial (num):
ans = 1
for i in range (1,num + 1):
ans *= i
return (ans)
In my mind ans remains one and is multiplied by every index on 1 through nums + 1. So it would look like: (1 * 1, 1 * 2, 1 * 3,...). How does this function lead to the factorial of the number in the parameter?

Why not introduce some print statements in your code to see what is going on?
def factorial(num):
ans = 1
for i in range(1, num + 1):
print(f" ans = {ans}, going to multiply by {i}")
ans *= i
return ans
print("Trying to find the factorial of 5")
final = factorial(5)
print(f"Final answer is: {final}")
This gives:
Trying to find the factorial of 5
ans = 1, going to multiply by 1
ans = 1, going to multiply by 2
ans = 2, going to multiply by 3
ans = 6, going to multiply by 4
ans = 24, going to multiply by 5
Final answer is: 120
So bottom line, you need to better understand what *= is doing in ans *= i (aka in-place operators), see here: https://docs.python.org/3/library/operator.html#in-place-operators

a *= b means :
take the content of a,
multiply it by b,
and store the result into a again.
(a in my example is ans for you)
So there is one variable, the same is used for every iteration. There is no list or such as you think it does, that takes the role of growing until the big final result.
ans starts at the value of 1, then will be multiplied by 2, and the result will replace it so it becomes 2, then will be multiply by 3, so it becomes 1 * 2 * 3 = 6, etc..
By the way, sometimes we call this kind of variable an "accumulator", in algorithmics.

Note the usage of the *= operator - in each iteration of the loop ans is multiplied by i, and the result saved back to ans.
Let's look at the first couple of iterations:
i=1 - ans * i is 1*1, or 1, which is saved back in ans.
i=2 - ans * i is 1*2, or 2, which is saved back in ans.
i=3 - ans * i is 2*3, or 6, which is saved back in ans.
... and so on.

Related

N = 10, = 100, = 1000 in a range [duplicate]

This question already has answers here:
Sum of the integers from 1 to n
(11 answers)
Closed 3 months ago.
I have the the sum from (i = 1) to N is 1 + 2 + 3 + 4 ... + N
I found this program to calculate the sum for i in range(1,100)
num1, num2 = 1, 100
sum = int((num2*(num2+1)/2) - (num1*(num1+1)/2) + num1)
print(sum)
This works, but what if I want to know N = 10, or N = 100?
Here is a better way to do that:
def sum(n):
return int(n * (n + 1) // 2)
print(sum(10))
print(sum(100))
This program works by pairing the numbers together from the end to the beginning. For example, to find the sum of the list 1, 2, 3, 4, 5, 6, you can pair 1 and 6 to make 7, 2 and 5 to make 7, and 3 and 4 to make 7. See a pattern? (hint: the pairs always add up to the sum of the first and the last).
This program also includes an adjustment for lists with an odd number of elements. For example, in the list 1, 2, 3, one needs to add the additional middle number that cannot be in a pair. 1 and 3 can pair to 4, but you'll need to add the unpaired 2 to the sum.
Now that you understand it, all you need to do is extract it into a function. Like this:
def consecutiveSum(num2):
num1 = 1
return int((num2*(num2+1)/2) - (num1*(num1+1)/2) + num1)
print(consecutiveSum(10)) # => 55
print(consecutiveSum(100)) # => 5050
Jiho Kim's answer also points out that this can be optimized a bit. See his answer too.
Do you know the formula for calculating the sum of an arithmetic progression? In the specific case of summing from 1 through N, it is N * (N + 1) / 2. Why does a different one work in your example? Because num1 * (num1 + 1) / 2 = 1 = num1 so your method reduces to num2 * (num2 + 1) / 2.

Improving performance of finding out how many possible triangles can be made with a given stick

I am doing an assessment that is asking by the given "n" as input which is a length of a stick; how many triangles can you make? (3 < n < 1,000,000)
For example:
input: N=8
output: 1
explanation:
(3,3,2)
input: N=12
output: 3
explanation:
(4,4,4) (4,5,3) (5,5,2)
Now the codes I wrote are returning 33 % accuracy as the web assessment is throwing time limit error.
ans = 0
n = int(input())
for a in range(1, n + 1):
for b in range(a, n - a + 1):
c = n - a - b
if a + b > c >= b:
ans += 1
print(ans)
code b:
ans = 0
n = int(input())
for i in range(1,n):
for j in range(i,n):
for c in range(j,n):
if(i+j+c==n and i+j>c):
ans+=1
print(ans)
How can this be made faster?
This is an intuitive O(n) algorithm I came up with:
def main():
n = int(input())
if n < 3:
print(0)
return
ans = n % 2
for a in range(2, n//2+1):
diff = n - a
if diff // 2 < a:
break
if diff % 2 == 0:
b = diff // 2
else:
b = diff // 2 + 1
b = max(b - a // 2, a)
c = n - b - a
if abs(b - c) >= a:
b += 1
c -= 1
ans += abs(b-c)//2 + 1
print(ans)
main()
I find the upper bound and lower bound for b and c and count the values in that range.
I thought of a completely different way to do it:
We take the smallest side and call it a. It can never be more than n/3, otherwise a different side would be the smallest.
We try to figure out what is the next smallest side (b):
We see what's left after reducing our a.
We divide it by 2 in order to find the middle where we'll start advancing from
We'll see how far we can get before the difference between the lengths is a (or the difference from the middle is a/2) as that's the minimum b side length that is possible and satisfies a+b>c. Basically, the second smallest side is a/2 less than the middle.
The smallest side is the maximum between our calculation or a, in caseb==a. b can never be lower than a as it violates our first rule that a is the smallest.
We figure out the difference from the middle and the smallest side. That's how many possible solutions we have for the other 2 sides.
Add everything together for every a and that's our solution.
The floor, ceil and % are fixes for when a is odd, the middle is .5, or +1 in case b+c is even, cause b==c is then possible.
Code:
import math
n = int(input("Enter a number: "))
total = 0
# a is the shortest side
for a in range(1, (n//3)+1):
length_left = n-a
middle_number = length_left/2
# Shortest potential side b where the distance between b and c is smaller than a (c-b < a)
b = middle_number-(math.ceil(a/2)-1)-((length_left % 2)/2)
# We calculate how far it is from the middle
max_distance_from_middle = middle_number - max(b, a)
# Add another 1 if the length is even, in case b==c
adding = math.floor(max_distance_from_middle) + (1 if length_left % 2 == 0 else 0)
total += adding
print(total)
Or in an ugly one-liner:
n = int(input("Enter a number: "))
print(sum(math.floor((n-a)/2 - max((n-a)/2 - math.ceil(a/2) + 1 - (((n-a) % 2)/2), a)) + 1 - ((n-a) % 2) for a in range(1, (n//3)+1)))
Alcuin's sequence expansion: O(1)
Alcuin's sequence [See: https://en.wikipedia.org/wiki/Alcuin%27s_sequence] is a series expansion of the polynomial below, where the nth coefficient corresponds to the nth answer, that is, the maximum amount of unique integer triangles with perimeter n.
The algorithmic implementation of this is simply a formula. The Online Encyclopaedia of Integer Sequences (OEIS) provides many formulas that achieve this, the simplest of which is:
round(n^2 / 48) (Even)
round((n+3)^2 / 48) (Odd)
[See: https://oeis.org/A005044]
This evidently has a constant time complexity, given that the only functions required are modulo 2, integer squared and round, each of which are constant time (under certain definitions).
Implementation
Expanded:
def triangles(n):
if n % 2 == 0:
return round(n ** 2 / 48)
else:
return round((n + 3) ** 2 / 48)
1-Liner:
def triangles(n): return round(n ** 2 / 48) if n%2==0 else round((n + 3) ** 2 / 48)
Or even:
def triangles(n): return round((n + 3 * n%2) ** 2 / 48)
Extra
No imports are needed.
As the OP questioned, why do we divide by 48? While I can't answer that explicitly, let's get an intuitive understanding. We are squaring numbers, so it is evidently going to expand greatly. By the time we get to 5, that would give 64 (8^2). So, there must be a constant (albeit a reciprocal) to restrict the growth of the parabola, thus the / 48.
When we graph the OP's method, it gives an alternating parabola. This explains why there is a back-and-forth with the +3 and +0.
https://mathworld.wolfram.com/AlcuinsSequence.html
import math
n = int(input())
print(round(n ** 2 / 48)) if n % 2 == 0 else print(round((n + 3)** 2 / 48))

A twist in Fibonacci's sequence in Python

I am studyng recursion in Python and now I am having a problem with this exercise:
Remember that Fibonacci's sequence is a sequence of numbers where every number is the sum of the previous two numbers.
For this problem, implement Fibonacci recursively, with a twist! Imagine that we want to create a new number sequence called Fibonacci-3. In Fibonacci-3, each number in the sequence is the sum of the previous three numbers. The
sequence will start with three 1s, so the fourth Fibonacci-3
number would be 3 (1+1+1), the fifth would be 5 (1+1+3), the sixth would be 9 (1+3+5), the seventh would be 17 (3+5+9), etc.
Name your function fib3, and make sure to use recursion.
The lines below will test your code.
If your function is correct, they will print 1, 3, 17, and 57.
print(fib3(3))
print(fib3(4))
print(fib3(7))
print(fib3(9))
This is the code until now:
def fib3(n):
if n <= 1:
return n
else:
return(fib3(n-1) + fib3(n-2) + fib3(n-3))
But the results are: 1, 2, 11, 37
Can you help me please to correct it?
The same thing other people are saying
As others have noted, you have to return 1 when n <= 3
def fib3 (n):
if n <= 3:
return 1
else:
return fib3(n - 1) + fib3(n - 2) + fib3(n - 3)
print(fib3(3)) # 1
print(fib3(4)) # 3
print(fib3(7)) # 17
print(fib3(9)) # 57
... but you can do better than that
But that definition of fib3 is junk. It does an insane amount of computation duplication. For example, fib3(40) takes over 30 minutes to compute due to O(n3) complexity
Consider an approach that uses an auxiliary loop with state variables – The O(n) complexity allows it to compute the same result in less than a millisecond.
def fib3 (n):
def aux (n,a,b,c):
if n == 1:
return a
else:
return aux(n-1,b,c,a+b+c)
return aux(n,1,1,1)
print(fib3(3)) # 1
print(fib3(4)) # 3
print(fib3(7)) # 17
print(fib3(9)) # 57
print(fib3(40)) # 9129195487
Fibonacci as a generic program: fibx
We can make generic the entire process of generating fibonacci sequences, but first we have to address something with your fib3 function. In general, Fibonacci numbers have a 0th term - ie, fib(0) == 0, fib(1) == 1. In your function, it looks like the first number is fib3(1), where fib3(0) would produce an undefined result.
Below, I'm going to introduce fibx which can take any binary operator and any seed values and create any fibonacci sequence we can imagine
from functools import reduce
def fibx (op, seed, n):
[x,*xs] = seed
if n == 0:
return x
else:
return fibx(op, xs + [reduce(op, xs, x)], n - 1)
Now we can implement standard fibonacci using fibx with the add (+) operator and seed values 0,1
from operator import add
def fib (n):
return fibx(add, [0,1], n)
print(fib(0)) # 0
print(fib(1)) # 1
print(fib(2)) # 1
print(fib(3)) # 2
print(fib(4)) # 3
print(fib(5)) # 5
Implementing fib3 using fibx
We can use the same fibx with the add operator to implement your fib3 function, but because of your 1-based index, notice I'm offsetting n by 1 to get the correct output
from operator import add
def fib3 (n):
return fibx(add, [1,1,1], n-1)
print(fib3(3)) # 1
print(fib3(4)) # 3
print(fib3(7)) # 17
print(fib3(9)) # 57
I'd recommend you start with a 0-based index tho. This means 0-based index fib3(2) is actually equal to your 1-based index of fib3(3)
from operator import add
def fib3 (n):
return fibx(add, [1,1,1], n)
print(fib3(2)) # 1
print(fib3(3)) # 3
print(fib3(6)) # 17
print(fib3(8)) # 57
Any imaginable sequence using fibx
And of course you can make any other sequence you can imagine. Here we make weirdfib that uses multiplication (*) instead of addition (+) to combine terms and has a starting seed of [1,2,3]
from operator import mul
def weirdfib (n):
return fibx(mul, [1,2,3], n)
print(weirdfib(0)) # 1
print(weirdfib(1)) # 2
print(weirdfib(2)) # 3
print(weirdfib(3)) # 6
print(weirdfib(4)) # 36
print(weirdfib(5)) # 648
print(weirdfib(6)) # 139968
Your problem description tells you why:
The sequence will start with three 1s
Your solution, however only returns 1 for n == 1 or lower:
if n <= 1:
return n
This means that for n == 2 (which should still return 1), you'd instead return fib3(2-1) + fib3(2-2) + fib3(2-3), or fib3(1) + fib3(0) + fib(-1), which thanks to the above test, then bottoms out to produce 1 + 0 + -1 == 0.
For n == 3, you'd return fib3(2) + fib3(1) + fib3(0); we worked out above that fib3(2) is 0, so the end result is 0 + 1 + 0 is the 1 you observed.
Finally, the 4th fib3 number (n == 4), does not return 3, but fib3(3) + fib3(2) + fib3(1) == 1 + 0 + 1 == 2.
Change that first test return 1 for n <= 3, to fix those first 3 values in the series:
def fib3(n):
if n <= 3:
return 1
else:
return fib3(n-1) + fib3(n-2) + fib3(n-3)
Now the code passes the given tests:
>>> def fib3(n):
... if n <= 3:
... return 1
... else:
... return fib3(n-1) + fib3(n-2) + fib3(n-3)
...
>>> print(fib3(3))
1
>>> print(fib3(4))
3
>>> print(fib3(7))
17
>>> print(fib3(9))
57
If n <= 1, the situation is a little more complex than just return n.
Consider the case of n = 4: your recursive call will be fib(3), fib(2), and fib(1).
The lattermost returns 1 immediately, which is what you want. However, the two recursive calls do some weird things. fib(2) recurses into fib(1), fib(0), and fib(-1), the return values for which basically hand back a big fat 0. fib(3) recurses into fib(2) (which we saw is 0), fib(1) (which works, and is 1), and fib(0) (which is also 0).
Hence, you get the 1 from the very beginning, and the 1 from the recursed fib(1) component of fib(3). There's your 2!
Basically, you want to make sure your base case can't return a negative number. Fix that (return either 1 or 0), and you should be good. As Martijn Pieters mentioned, you can also make your base case n <= 3 and it should achieve the same effect.
Let me contribute with perhaps the most optimal "pythonic" answer.
The main point is to avoid recursive function calls to optimise the efficiency of the code. Pythonic way of thinking would involve the following compact code, which is an iterative creation of the Fibonacci sequence of n numbers, including the seed numbers [1, 1, 1].
def fibonacci_sequence(n):
x = [1, 1, 1]
[x.append(x[-1] + x[-2] + x[-3]) for i in range(n - len(x))]
return x
import time
n = int(raw_input("Enter the size of Fibonacci-3 sequence: "))
start_time = time.time()
print fibonacci_sequence(n)
print "The time to compute the Fibonacci-3 sequence is: %s" % (time.time() - start_time)

Sequence of exponentially growing numbers in python

Given a number and a ratio, how do I create an exponentially growing list of numbers, whose sum equals the starting number?
>>> r = (1 + 5 ** 0.5) / 2
>>> l = makeSeq(42, r)
>>> l
[2.5725461188664465, 4.162467057952537, 6.735013176818984,
10.897480234771521, 17.63249341159051]
>>> sum(l)
42.0
>>> l[-1]/l[-2]
1.6180339887498953
>>> r
1.618033988749895
A discrete sequence of exponentially growing numbers is called a geometric progression. The sum is called a geometric series. The formula here can easily be solved to produce the sequence you need:
>>> n = 5
>>> r = (1 + 5 ** 0.5) / 2
>>> r
1.618033988749895
>>> total = 2.28
>>> a = total * (1 - r) / (1 - r ** n)
>>> a
0.13965250359560707
>>> sequence = [a * r ** i for i in range(n)]
>>> sequence
[0.13965250359560707, 0.22596249743170915, 0.36561500102731626, 0.5915774984590254, 0.9571924994863418]
>>> sum(sequence)
2.28
>>> sequence[1] / sequence[0]
1.618033988749895
>>> sequence[2] / sequence[1]
1.618033988749895
>>> sequence[2] / sequence[1] == r
True
It's also worth noting that both this problem and the original problem of the Fibonacci could be solved using a binary search / bisection method.
Pick any sequence of Fibonacci numbers you want. Add them up, and divide your target number by the sum to get a scaling factor. Multiply each number in your chosen sequence by the scaling factor, and you'll have a new sequence that sums to your target, and has the same ratio of adjacent terms as the original sequence of Fibonacci numbers.
To generate the example in your question, note that 1 + 2 + 3 + 5 + 8 = 19, and 2.28/19 = 0.12.
The Fibonacci sequence goes as follows: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ... etc. As you may have already seen in the comments on your question, the Fibonacci sequence itself doesn't "scale" (i.e., fib_seq * 0.12 = 0, 0.12, 0.12, 0.24, 0.36, 0.60, 0.96 ... etc. isn't the Fibonacci sequence any longer), so you you can really only make a Fibonacci series in the order the values are presented above. If you would like to make the Fibonacci sequence dynamically scalable depending on some criteria, please specify further what purpose that would serve and what you are having trouble with so that the community can help you more.
Now, let's start with the basics. If you've had trouble with implementing a function to print the Fibonacci Sequence in the first place, refer to the answer #andrea-ambu gives here: https://stackoverflow.com/a/499245/5209610. He provides a very comprehensive explanation of how to not only implement the Fibonacci Sequence in a function in any given language, but even goes further to explore how to do so efficiently!
I presume that you are trying to figure out how to write a function that will take a user-provided integer and print out the Fibonacci series that sums up to that value (i.e., print_fib_series(33) would print 0 + 1 + 1 + 2 + 3 + 5 + 8 + 13). This is fairly easily achievable by just incrementally adding the next value in the Fibonacci series until you arrive to the user-provided value (and keeping track of which values you've summed together so far), assuming that the user-provided value is a sum of Fibonacci series values. Here's an easy implementation of what I just described:
# Recursive implementation of the Fibonacci sequence from the answer I linked
def fib_seq(ind):
if ind == 0:
return 0;
elif ind == 1:
return 1;
else:
return fib_seq(ind - 1) + fib_seq(ind - 2);
def list_fib_series(fib_sum, scaling_factor):
output_list = [];
current_sum = 0;
for current_val in fib_seq():
current_sum += current_val * scaling_factor;
output_list.append(current_val);
if current_sum == fib_sum:
return output_list;
elif current_sum > fib_sum:
return 0; # Or you could raise an exception...
fib_list = list_fib_series(2.4, 0.12):
print ' + '.join(map(str, fib_list));
So, considering the decimal value of 2.4 you could apply a linear scaling factor of 0.12 to the Fibonacci series and get the result you indicated in your question. I hope this helps you out!
Forget about the decimal numbers, like julienc mentioned program would never know where to start from if you bend the 'definition of Fibonacci series' like the way you wish to. You must be definitive about fibonacci series here.
For whole numbers and actual definition of fibonacci series, best you can do is make a program which takes number as input and tells whether the number sums up to some fibonacci series. And if it does then print the series. Assuming this is what you want.
a = 33
f_list = []
def recur_fibo(n):
if n <= 1:
return n
else:
return(recur_fibo(n-1) + recur_fibo(n-2))
i=0
total = 0
while True:
num = recur_fibo(i)
total += num
f_list.append(num)
if total > a:
print "Number can not generate fibonacci series"
break
elif total == a:
print "Series: %s" % f_list
break
i +=1
Output:
Series: [0, 1, 1, 2, 3, 5, 8, 13]
Based off of Alex Hall's answer, this is what I ended up using:
def geoProgress(n, r=(1 + 5 ** 0.5) / 2, size=5):
""" Creates a Geometric Progression with the Geometric sum of <n>
>>> l = geoProgress(42)
>>> l
[2.5725461188664465, 4.162467057952537, 6.735013176818984,
10.897480234771521, 17.63249341159051]
>>> sum(l)
42.0
>>> l[-1]/l[-2]
1.6180339887498953
"""
return [(n * (1 - r) / (1 - r ** size)) * r ** i for i in range(size)]

Python Homework - sum of perfect squares

I need help with a python homework question.
"Assume there is a variable , h already associated with a positive integer value. Write the code necessary to compute the sum of the perfect squares whose value is less than h, starting with 1. (A perfect square is an integer like 9, 16, 25, 36 that is equal to the square of another integer (in this case 3*3, 4*4, 5*5, 6*6 respectively).) Associate the sum you compute with the variable q. For example, if h is 19, you would assign 30 to q because the perfect squares (starting with 1) that are less than h are: 1, 4, 9, 16 and 30==1+4+9+16."
So far I get really close to having it right but it always does one extra number than it needs. For example with putting in 19, instead of stopping at 1,4,9,16 it adds 25 too.
heres my code so far
h_i=input()
h=int(h_i)
s=0
q=0
total=s**2
while total<=h:
s+=1
total=s**2
q+=total
print(total)
print(q)
I am going to suggest a different approach to this using a more "Pythonic" way with list comprehension:
>>> highest = 19 # in your case this is h
lst = list (n**2 for n in range(1, highest + 1))
lst
[1, 4, 9, 16]
>>> print '\n'.join(str(p) for p in lst)
1
4
9
16
I would suggest modifying your code to improve readability and spacing. Additionally, you can start counting at 1 (i = 1) since you state a positive integer must be given.
h = int(input('insert positive integer: '))
i = 1
total = 0
while total <= h:
total += i ** 2
i += 1
print(total)
And now... for something completely different:
h = int(input())
n = int((h - 1) ** 0.5)
q = n * (n + 1) * (2*n + 1) // 6
print(q)
You need to put s+=1 and total=s**2 at the end of your loop, so that the condition (which I believe should be total<h) is checked before it's added to q.
h_i=input()
h=int(h_i)
s=0
q=0
total=s**2
while total<h:
q+=total
print(total)
s+=1
total=s**2
print(q)
What you care about is that the current value of n**2 is less than h. So make sure you test that value.
h = 19
n = 1
q = 0
while n**2 <= h:
q += n**2
n += 1
print("Sum of squares less than {} is: {}".format(h, q))
while I love simplicity, here is my take and I have tested in the lab, it works:
q=0
n=0
while n*n<h:
q+=n*n
n+=1

Categories