Sequence of exponentially growing numbers in python - 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)]

Related

Python: take multiples based on condition

Is there a Way in Python to have a for loop which cycle only on multiples of a given number that are not multiples of any number lower than given number?
I mean something like this:
if given_number = 13
the for loop is going to cycle only on [13 * 13, 13 * 17, 13 * 19, 13 * 23, 13*29, 13*31, 13*39, ........]
I came across this kind of problem working on this function:
def get_primes_lower_n(n: int) -> List[int]:
"""
n: int
the given input number
returns: List[int]
all primes number lower than given input number
raises:
ValueError: the given input is an integer < 2
TypeError: the given input is not an integer
"""
if not isinstance(n, int):
raise TypeError("an integer is required")
if n < 2:
raise ValueError("an integer > 1 is required")
primes = np.ones(n + 1, dtype=bool) # bool(1) = True
primes[:2] = False
primes[4:: 2] = False
for i in range(3, isqrt(n) + 1, 2):
if primes[i]:
primes[i ** 2:: 2 * i] = False
return np.where(primes == True)[0]
if n is something like 9 * 10 ** 9 the algorithm is going to explode. For any value of I primes[i ** 2:: 2 * i] = False is going to take more or less 52 seconds. Let's think of I = 7; primes[i ** 2:: 2 * i] = False
is going to set to False all values in positions multiples of 21 and 35 that are already set to False.
As the value of I increases, I expect the time of execution of this operation primes[i ** 2:: 2 * i] = False to take less time (less values need to be set), but instead it increases exponentially. Why?
To answer your first question:
Is there a Way in python to have a for loop which cycle only on multiples of a given number that are not multiples of any number lower than given number?
Yes there is, but not efficient enough (unless you find a faster implementation).
Let n be the number we are looking at.
The numbers that are not multiples of any number lower than n are exactly the numbers left from the sieve when ran up to n. Therefore, these numbers are already present in the array, they are the True values with index greater than n. Unfortunately, as these are stored by index, finding them is expensive and finally makes the code go slower, as the collisions from the original algorithm are so rare. Still, here is a possible implementation in the for loop.
for i in range(3, isqrt(n) + 1, 2):
primes[i*(np.nonzero(primes[i:n//i])[0]+i)] = False
# [i:n//i] is to bound the search from i to the last number such
# that i*(n//i) < n.
Here is an equivalent code without the bool array:
def get_primes_lower_n(n: int) -> list[int]:
primes = np.arange(3, n + 1, 2) # only odd numbers over 3
val = 0
idx = -1
while val <= isqrt(n)+1:
idx += 1
val = primes[idx]
primes = np.setdiff1d(primes, val*primes[idx:idx+bisect.bisect_left(primes[idx:], n//val+1)])
return np.insert(primes, 0, 2)
As a conclusion, it is worth it to set the same values multiple times rather than use an exact approch that is slower.
Sorry for the lack of working solution but i hope this can help you in some way. If you find an interesting algorithm, feel free to let me know!

Errors in Directly vs Recursively Calculating a given Fibonacci Number

I was bored at work and was playing with some math and python coding, when I noticed the following:
Recursively (or if using a for loop) you simply add integers together to get a given Fibonacci number. However there is also a direct equation for calculating Fibonacci numbers, and for large n this equation will give answers that are, frankly, quite wrong with respect to the recursively calculated Fibonacci number.
I imagine this is due to rounding and floating point arithmetic ( sqrt(5) is irrational after all), and if so can anyone point me into a direction on how I could modify the fibo_calc_direct function to return a more accurate result?
Thanks!
def fib_calc_recur(n, ii = 0, jj = 1):
#n is the index of the nth fibonacci number, F_n, where F_0 = 0, F_1 = 1, ...
if n == 0: #use recursion
return ii
if n == 1:
return jj
else:
return(fib_calc_recur(n -1, jj, ii + jj))
def fib_calc_direct(n):
a = (1 + np.sqrt(5))/2
b = (1 - np.sqrt(5))/2
f = (1/np.sqrt(5)) * (a**n - b**n)
return(f)
You could make use of Decimal numbers, and set its precision depending on the magninute of n
Not your question, but I'd use an iterative version of the addition method. Here is a script that makes both calculations (naive addition, direct with Decimal) for values of n up to 4000:
def fib_calc_iter(n):
a, b = 0, 1
if n < 2:
return n
for _ in range(1, n):
a, b = b, a + b
return b
from decimal import Decimal, getcontext
def fib_calc_decimal(n):
getcontext().prec = n // 4 + 3 # Choose a precision good enough for this n
sqrt5 = Decimal(5).sqrt()
da = (1 + sqrt5) / 2
db = (1 - sqrt5) / 2
f = (da**n - db**n) / sqrt5
return int(f + Decimal(0.5)) # Round to nearest int
# Test it...
for n in range(1, 4000):
x = fib_calc_iter(n)
y = fib_calc_decimal(n)
if x != y:
print(f"Difference found for n={n}.\nNaive method={x}.\nDecimal method={y}")
break
else:
print("No differences found")

How to find sum of cubes of the divisors for every number from 1 to input number x in python where x can be very large

Examples,
1.Input=4
Output=111
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
------------------------
sum = 111(output)
1.Input=5
Output=237
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
5 = 1³ + 5³(divisors of 5)
-----------------------------
sum = 237 (output)
x=int(raw_input().strip())
tot=0
for i in range(1,x+1):
for j in range(1,i+1):
if(i%j==0):
tot+=j**3
print tot
Using this code I can find the answer for small number less than one million.
But I want to find the answer for very large numbers. Is there any algorithm
for how to solve it easily for large numbers?
Offhand I don't see a slick way to make this truly efficient, but it's easy to make it a whole lot faster. If you view your examples as matrices, you're summing them a row at a time. This requires, for each i, finding all the divisors of i and summing their cubes. In all, this requires a number of operations proportional to x**2.
You can easily cut that to a number of operations proportional to x, by summing the matrix by columns instead. Given an integer j, how many integers in 1..x are divisible by j? That's easy: there are x//j multiples of j in the range, so divisor j contributes j**3 * (x // j) to the grand total.
def better(x):
return sum(j**3 * (x // j) for j in range(1, x+1))
That runs much faster, but still takes time proportional to x.
There are lower-level tricks you can play to speed that in turn by constant factors, but they still take O(x) time overall. For example, note that x // j == 1 for all j such that x // 2 < j <= x. So about half the terms in the sum can be skipped, replaced by closed-form expressions for a sum of consecutive cubes:
def sum3(x):
"""Return sum(i**3 for i in range(1, x+1))"""
return (x * (x+1) // 2)**2
def better2(x):
result = sum(j**3 * (x // j) for j in range(1, x//2 + 1))
result += sum3(x) - sum3(x//2)
return result
better2() is about twice as fast as better(), but to get faster than O(x) would require deeper insight.
Quicker
Thinking about this in spare moments, I still don't have a truly clever idea. But the last idea I gave can be carried to a logical conclusion: don't just group together divisors with only one multiple in range, but also those with two multiples in range, and three, and four, and ... That leads to better3() below, which does a number of operations roughly proportional to the square root of x:
def better3(x):
result = 0
for i in range(1, x+1):
q1 = x // i
# value i has q1 multiples in range
result += i**3 * q1
# which values have i multiples?
q2 = x // (i+1) + 1
assert x // q1 == i == x // q2
if i < q2:
result += i * (sum3(q1) - sum3(q2 - 1))
if i+1 >= q2: # this becomes true when i reaches roughly sqrt(x)
break
return result
Of course O(sqrt(x)) is an enormous improvement over the original O(x**2), but for very large arguments it's still impractical. For example better3(10**6) appears to complete instantly, but better3(10**12) takes a few seconds, and better3(10**16) is time for a coffee break ;-)
Note: I'm using Python 3. If you're using Python 2, use xrange() instead of range().
One more
better4() has the same O(sqrt(x)) time behavior as better3(), but does the summations in a different order that allows for simpler code and fewer calls to sum3(). For "large" arguments, it's about 50% faster than better3() on my box.
def better4(x):
result = 0
for i in range(1, x+1):
d = x // i
if d >= i:
# d is the largest divisor that appears `i` times, and
# all divisors less than `d` also appear at least that
# often. Account for one occurence of each.
result += sum3(d)
else:
i -= 1
lastd = x // i
# We already accounted for i occurrences of all divisors
# < lastd, and all occurrences of divisors >= lastd.
# Account for the rest.
result += sum(j**3 * (x // j - i)
for j in range(1, lastd))
break
return result
It may be possible to do better by extending the algorithm in "A Successive Approximation Algorithm for Computing the Divisor Summatory Function". That takes O(cube_root(x)) time for the possibly simpler problem of summing the number of divisors. But it's much more involved, and I don't care enough about this problem to pursue it myself ;-)
Subtlety
There's a subtlety in the math that's easy to miss, so I'll spell it out, but only as it pertains to better4().
After d = x // i, the comment claims that d is the largest divisor that appears i times. But is that true? The actual number of times d appears is x // d, which we did not compute. How do we know that x // d in fact equals i?
That's the purpose of the if d >= i: guarding that comment. After d = x // i we know that
x == d*i + r
for some integer r satisfying 0 <= r < i. That's essentially what floor division means. But since d >= i is also known (that's what the if test ensures), it must also be the case that 0 <= r < d. And that's how we know x // d is i.
This can break down when d >= i is not true, which is why a different method needs to be used then. For example, if x == 500 and i == 51, d (x // i) is 9, but it's certainly not the case that 9 is the largest divisor that appears 51 times. In fact, 9 appears 500 // 9 == 55 times. While for positive real numbers
d == x/i
if and only if
i == x/d
that's not always so for floor division. But, as above, the first does imply the second if we also know that d >= i.
Just for Fun
better5() rewrites better4() for about another 10% speed gain. The real pedagogical point is to show that it's easy to compute all the loop limits in advance. Part of the point of the odd code structure above is that it magically returns 0 for a 0 input without needing to test for that. better5() gives up on that:
def isqrt(n):
"Return floor(sqrt(n)) for int n > 0."
g = 1 << ((n.bit_length() + 1) >> 1)
d = n // g
while d < g:
g = (d + g) >> 1
d = n // g
return g
def better5(x):
assert x > 0
u = isqrt(x)
v = x // u
return (sum(map(sum3, (x // d for d in range(1, u+1)))) +
sum(x // i * i**3 for i in range(1, v)) -
u * sum3(v-1))
def sum_divisors(n):
sum = 0
i = 0
for i in range (1, n) :
if n % i == 0 and n != 0 :
sum = sum + i
# Return the sum of all divisors of n, not including n
return sum
print(sum_divisors(0))
# 0
print(sum_divisors(3)) # Should sum of 1
# 1
print(sum_divisors(36)) # Should sum of 1+2+3+4+6+9+12+18
# 55
print(sum_divisors(102)) # Should be sum of 2+3+6+17+34+51
# 114

Sum a sequence of numbers

Given: Two positive integers a and b (a
Return: The sum of all odd integers from a through b, inclusively.
#My code:
a = 100
b = 200
for i in range(a,b):
if i%2 == 1:
print i
At the moment it's just showing a drop down list of all the odd integers. I do not know how to affix a "range" to this properly, if need be. How can I add on to my code above to get the sum of all the odd integers?
Thanks
Sum all the numbers between a and b if odd.
sum(i for i in xrange(a, b) if i%2)
A rather quick way to do it would be:
result = 0
for i in range(a,b+1):
if i%2 == 1:
result += i
print result
There are a bunch of ways to do this. If you think about the math, though, it's a lot like Gauss's old problem. Gauss was asked to add the numbers between 1 and 100, and he realized that each pair of high and low values summed to 101 (100 + 1, 99 + 2, 98 + 3…)
high = b
low = a
So we have to multiply some number of b + a values. How many are there? For all the integers, that's just
num_pairs = (high-low) // 2
Then we multiply that number by high + low to get the answer:
result = (high + low) * num_pairs
But you only want every other ones, so we divide by two again:
result //= 2
Totally:
def sumrange(low, high, step):
num_pairs = (high - low) // 2
result = (high + low) * num_pairs
return result // step
or sumrange = lambda low, high, step: (high - low) * (high + low) // (2 * step)
Now this still isn't quite an answer to your question, because it needs to be offset depending on whether your low value is odd, and whether your high value is included or excluded. But I will leave that as an exercise.
Making this a CW answer so someone can edit if my math is messy.
Some mathematical tricks can solve your problem much efficiently.
For example, sum of first n odd numbers = n*n square(n)
So you can use for
Sum of odd numbers [m,n] = n*n - (m-2)*(m-2) where m!=1 and m and n are odds
One more useful analysis is, AP (arithmetic progression)
Formula : (n/2)*(a+l) where n= no. of elements, a = first term, l= last term
Here,
a = m [if m is odd]
a = m+1 [if m is even]
l = n [if n is odd]
l = n-1 [if n is even]
n = ( ( l - a ) / 2 ) + 1
By applying in code, you can easily get the answer...
And the numpy version of the solution:
import numpy as np
a = 100
b = 200
r = np.linspace(a,b-1,b-a)
r = np.sum(np.mod(r,2)*r)
print(r)

Optimalization of the primes finding function

After 10 minutes of work I have written a function presented below. It returns a list of all primes lower than an argument. I have used all known for me programing and mathematical tricks in order to make this function as fast as possible. To find all the primes lower than a million it takes about 2 seconds.
Do you see any possibilities to optimize it even further? Any ideas?
def Primes(To):
if To<2:
return []
if To<3:
return [2]
Found=[2]
n=3
LastSqr=0
while n<=To:
k=0
Limit=len(Found)
IsPrime=True
while k<Limit:
if k>=LastSqr:
if Found[k]>pow(n,0.5):
LastSqr=k
break
if n%Found[k]==0:
IsPrime=False
break
k+=1
if IsPrime:
Found.append(n)
n+=1
return Found
You can use a couple tricks to speed things up, using the basic sieve of erastothenes. One is to use Wheel Factorization to skip calculating numbers that are known not to be prime. For example, besides 2 and 3, all primes are congruent to 1 or 5 mod 6. This means you don't have to process 4 of every 6 numbers at all.
At the next level, all primes are congruent to 1, 7, 11, 13, 17, 19, 23, or 29, mod 30. You can throw out 22 of every 30 numbers.
Here is a simple implementation of the sieve of Erastothenes that doesn't calculate or store even numbers:
def basic_gen_primes(n):
"""Return a list of all primes less then or equal to n"""
if n < 2:
return []
# The sieve. Each entry i represents (2i + 1)
size = (n + 1) // 2
sieve = [True] * size
# 2(0) + 1 == 1 is not prime
sieve[0] = False
for i, value in enumerate(sieve):
if not value:
continue
p = 2*i + 1
# p is prime. Remove all of its multiples from the sieve
# p^2 == (2i + 1)(2i + 1) == (4i^2 + 4i + 1) == 2(2i^2 + 2i) + 1
multiple = 2 * i * i + 2 * i
if multiple >= size:
break
while multiple < size:
sieve[multiple] = False
multiple += p
return [2] + [2*i+1 for i, value in enumerate(sieve) if value]
As mentioned, you can use more exotic sieves as well.
You can check only odd numbers. So why don't you use n+=2 instead of n+=1?
google and wikipedia for better algorithms. If you are only looking for small primes this might be fast enough. But the real algorithms are a lot faster for large primes.
http://en.wikipedia.org/wiki/Quadratic_sieve
start with that page.
Increment n by two instead of one. ?

Categories