This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Python program to find fibonacci series. More Pythonic way.
Hey, i was trying to write a script which sums all the even terms in "Fibonacci Sequence" under 4 millions.
Fibonacci1 = 1
Fibonacci2 = 2
a = 2
i = 4
for i in range(1,4000000):
Fibonacci1 = Fibonacci1 + Fibonacci2
if Fibonacci1 % 2 == 0:
a = a + Fibonacci1
Fibonacci2 = Fibonacci1 + Fibonacci2
if Fibonacci2 % 2 == 0:
a = a + Fibonacci2
print a
raw_input()
it should takes less than a minute, but it took all night and it wasn't solved !
Edit: Sorry guys, i misunderstood the problem. I though it means that i have to sum all the even terms UP TO 4 million ! But the solution was to sum all the even terms UNTIL 4 million.
Working code (finished in less than one second):
Fibonacci1 = 1
Fibonacci2 = 2
a = 2
while a < 4000000:
Fibonacci1 = Fibonacci1 + Fibonacci2
if Fibonacci1 % 2 == 0:
a = a + Fibonacci1
Fibonacci2 = Fibonacci1 + Fibonacci2
if Fibonacci2 % 2 == 0:
a = a + Fibonacci2
print a
raw_input()
There are a couple of problems with your code:
You are looping four million times instead of until a condition is true.
You have repeated code in the body of your loop.
Most people when they start learning Python learn only imperative programming. This is not surprising because Python is an imperative language. But Python also supports functional programming to a certain extent and for this sort of exercise a functional programming approach is more enlightening in my opinion.
First define a generator that generates all the Fibonacci numbers:
def fib():
a = b = 1
while True:
yield a
a, b = b, a + b
To use this generator we can import a few useful functions from itertools. To print the first few numbers use islice:
from itertools import ifilter, islice, takewhile
for x in islice(fib(), 5):
print x
1
1
2
3
5
To find only the even numbers we can use ifilter to produce a new generator:
def is_even(x):
return x % 2 == 0
evenfibs = ifilter(is_even, fib())
for x in islice(evenfibs, 5):
print x
2
8
34
144
610
To fetch numbers from the generator until a number exceeds four million use takewhile:
for x in takewhile(lambda x: x < 4000000, evenfibs):
print x
To solve the problem you can use sum:
sum(list(takewhile(lambda x: x < 4000000, evenfibs)))
I hope this shows that a functional programming approach is not difficult and is a more elegant way to solve certain types of problem.
Are you sure it is i that you want to be less than 4 million?
You may be interested in knowing about the The On-Line Encyclopedia of Integer Sequences!
You can search information by name or by sequence.
If you search either for 0,2,8,34 or 'Even Fibonacci' you will be redirect to sequence A014445
There you you find lots of information including formulas,
from that to code a generator that will yield the even fibonacci numbers directly is easy.
def evenfib():
""" Generates the even fibonacci numbers """
a, b = 2, 0
while True:
a, b = b, a+4*b
yield a
The loop condition is wrong, it should be something like this:
while True:
Fibonacci1 = Fibonacci1 + Fibonacci2
if Fibonacci1 % 2 == 0:
if a + Fibonacci1 > 4000000:
break
a = a + Fibonacci1
Fibonacci2 = Fibonacci1 + Fibonacci2
if Fibonacci2 % 2 == 0:
if a + Fibonacci2 > 4000000:
break
a = a + Fibonacci2
Currently, you sum up all the first 2 million even Fibonacci numbers.
But that is not the task. You have to sum all even Fibonacci numbers that are below 4 million.
NOTE: This has been heavily modified to address the actual question
Here's an alternate (and very fast, but untested, method).
It relies on a few properties:
Each Fibonacci number can be calculated directly as floor( pow( phi, n ) + 0.5 ) (See Computation by Rounding in http://en.wikipedia.org/wiki/Fibonacci_number ). Conversely the index of the biggest Fibonacci number less than i is given by floor( log(i*sqrt(5)) / log(phi) )
The sum of the first N Fibonacci numbers is the N+2th fibonacci number minus 1 (See Second Identity on the same wikipedia page)
The even Fibonacci numbers are are every third number. ( Look at the sequence mod 2 and the result is trivial )
The sum of the even Fibonacci numbers is half the sum of the odd Fibonacci numbers upto the same point in the sequence. (This follows from 3. and the property that F(3N) = F(3N-1) + F(3N-2) so F(3N-2) + F(3N-1) + F(3N) = 2 F(N) .. then summing both sides.
So convert our maximum value of 4000000 calculate the index of the highest Fibonacci number
less than it.
int n = floor(log(4000000*sqrt(5))/log(phi)) = 33.
33 is divisible by 3 so it is an even Fibonacci number, if it wasn't we'd need to adjust n like this.
n = (n/3)*3
The sum of all Fibonacci numbers up to this point if given by
sum = floor( pow( phi, n+2 )/sqrt(5) + 0.5 ) - 1 = 9227464
The sum of all even numbers is half of this:
sum_even = 4613732
Nice thing about this is that its an O(1) (or O(log(N)) if you include the cost of pow/log) algorithm, and works on doubles.. so we can calculate the sum for very large values.
I don't exactly understand your algorithm, but it seems that smerriman has a point, 4000000 Fibonnacci sequence numbers would surely grow above 4M. I guess that the faster approach would be to generate sequence up to 4M, then adding up the even ones.
There are other tricks that make this more efficient than simply computing the complete list of Fibonacci numbers, and then summing the even numbers in the list.
I would, IF it were me trying to solve this problem, make a list of the even Fibonacci numbers. Are there any interesting characteristics of that list? Can you convince yourself that this pattern holds true in general?
Next, I might look for a way to compute the members of that list, and only those elements that are needed. I might even look to see if there are any formulas to be found that yield the sum of a sequence of Fibonacci numbers.
Of course, all of this would take up more of your own time than simply coding up the brute force solution, but Project Euler is all about finding the pretty solution rather than the brute force solution. In the end, if you have learned something about mathematics, about computation, then you have gained.
## nice simple generator Mark Byers
def fib():
a = b = 1
while True:
yield a
a, b = b, a + b
## does same as takewhile 5
for fibonacci in zip(range(1,1+5),fib()):
print "fib(%i) = %i" % fibonacci
## we can slice to take every second
print "even sequence upto 100th"
total=0
for fibonacci in zip(range(1,1+100),fib())[::2]:
print "fib(%i) = %i" % fibonacci
total+=fibonacci[1] ## to double check
print "Has sum: ", sum( b for a,b in zip(range(1,1+100),fib())[::2] ),'that is ',total
print "odd sequence upto 100th"
total=0
for fibonacci in zip(range(1,1+100),fib())[1::2]:
print "fib(%i) = %i" % fibonacci
total+=fibonacci[1] ## to double check
print "Has sum: ", sum( b for a,b in zip(range(1,1+100),fib())[1::2] ),'that is ',total
Come on, the optimal way to compute Fibonacci sequence is using 2 tricks:
EDITED, sorry for earlier mistake
1:
N =|2 0 0|
|1 0 0|
|0 0 0|
M =|3 2 1|
|2 1 0|
|0 0 1|
Matrix N*M^(n/3) has sum of first n fibonacci numbers (filtered only to the even ones) is the upper right element.
2:
You can use http://en.wikipedia.org/wiki/Exponentiation_by_squaring, because matrix multiplication is a ring.
So you can solve our problem in O(log n)
Related
I'm studing recursive function and i faced question of
"Print sum of 1 to n with no 'for' or 'while' "
ex ) n = 10
answer =
55
n = 100
answer = 5050
so i coded
import sys
sys.setrecursionlimit(1000000)
sum = 0
def count(n):
global sum
sum += n
if n!=0:
count(n-1)
count(n = int(input()))
print(sum)
I know it's not good way to get right answer, but there was a solution
n=int(input())
def f(x) :
if x==1 :
return 1
else :
return ((x+1)//2)*((x+1)//2)+f(x//2)*2
print(f(n))
and it works super well , but i really don't know how can human think that logic and i have no idea how it works.
Can you guys explain how does it works?
Even if i'm looking that formula but i don't know why he(or she) used like that
And i wonder there is another solution too (I think it's reall important to me)
I'm really noob of python and code so i need you guys help, thank you for watching this
Here is a recursive solution.
def rsum(n):
if n == 1: # BASE CASE
return 1
else: # RECURSIVE CASE
return n + rsum(n-1)
You can also use range and sum to do so.
n = 100
sum_1_to_n = sum(range(n+1))
you can try this:
def f(n):
if n == 1:
return 1
return n + f(n - 1)
print(f(10))
this function basically goes from n to 1 and each time it adds the current n, in the end, it returns the sum of n + n - 1 + ... + 1
In order to get at a recursive solution, you have to (re)define your problems in terms of finding the answer based on the result of a smaller version of the same problem.
In this case you can think of the result sumUpTo(n) as adding n to the result of sumUpTo(n-1). In other words: sumUpTo(n) = n + sumUpTo(n-1).
This only leaves the problem of finding a value of n for which you know the answer without relying on your sumUpTo function. For example sumUpTo(0) = 0. That is called your base condition.
Translating this to Python code, you get:
def sumUpTo(n): return 0 if n==0 else n + sumUpTo(n-1)
Recursive solutions are often very elegant but require a different way of approaching problems. All recursive solutions can be converted to non-recursive (aka iterative) and are generally slower than their iterative counterpart.
The second solution is based on the formula ∑1..n = n*(n+1)/2. To understand this formula, take a number (let's say 7) and pair up the sequence up to that number in increasing order with the same sequence in decreasing order, then add up each pair:
1 2 3 4 5 6 7 = 28
7 6 5 4 3 2 1 = 28
-- -- -- -- -- -- -- --
8 8 8 8 8 8 8 = 56
Every pair will add up to n+1 (8 in this case) and you have n (7) of those pairs. If you add them all up you get n*(n+1) = 56 which correspond to adding the sequence twice. So the sum of the sequence is half of that total n*(n+1)/2 = 28.
The recursion in the second solution reduces the number of iterations but is a bit artificial as it serves only to compensate for the error introduced by propagating the integer division by 2 to each term instead of doing it on the result of n*(n+1). Obviously n//2 * (n+1)//2 isn't the same as n*(n+1)//2 since one of the terms will lose its remainder before the multiplication takes place. But given that the formula to obtain the result mathematically is part of the solution doing more than 1 iteration is pointless.
There are 2 ways to find the answer
1. Recursion
def sum(n):
if n == 1:
return 1
if n <= 0:
return 0
else:
return n + sum(n-1)
print(sum(100))
This is a simple recursion code snippet when you try to apply the recurrent function
F_n = n + F_(n-1) to find the answer
2. Formula
Let S = 1 + 2 + 3 + ... + n
Then let's do something like this
S = 1 + 2 + 3 + ... + n
S = n + (n - 1) + (n - 2) + ... + 1
Let's combine them and we get
2S = (n + 1) + (n + 1) + ... + (n + 1) - n times
From that you get
S = ((n + 1) * n) / 2
So for n = 100, you get
S = 101 * 100 / 2 = 5050
So in python, you will get something like
sum = lambda n: ( (n + 1) * n) / 2
print(sum(100))
Heads up: apologies for my poor style, inefficient code, and general stupidity. I'm doing this purely out of interest. I have no delusions that I will become a professional programmer.
How would solve this problem (assuming it can be solved). To be clear you want to take in an int x and an int y and return some expression in terms of y that equals x. For example if I passed in 9 and 2 one of the shortest solutions (I'm pretty sure) would be ((2+2)x2)+(2/2) with 4 total operators. You can assume positive integers because that's what I'm doing for the most part.
I have found a fastish partial solution that returns a solution for whatever numbers, but usually not the smallest one. Here it is coded in python:
def re_express(n, a, expression):
if n==0:
print(expression)
else:
if a**a < n:
n -= a**a
expression += "+" + str(a) + "^" +str(a)
re_express(n, a, expression)
elif a*a < n:
n -= a*a
expression += "+" + str(a) + "*" + str(a)
re_express(n, a, expression)
elif a < n:
n -= a
expression += "+" + str(a)
re_express(n, a, expression)
else:
n -= 1
expression += "+" + str(a) + "/" + str(a)
re_express(n, a, expression)
I have also think I have one that returns a pretty small solution, but it is not guaranteed to be the smallest solution. I hand simulated it and it got the 2 and 9 example correct, whereas my first algorithm produced a 5 operator solution: 2^2+2^2+2/2. But it gets slow quickly for large n's. I wrote it down in pseudocode.
function re_express(n, a, children, root, solutions):
input: n, number to build
a, number to build with
children, an empty array
root, a node
solutions, an empty dictionary
if not root:
root.value = a
if the number of layers in the tree is greater than the size of the shortest solution, return the shortest solution
run through each mathematical operator and create a child node of root as long as the child will have a unique value
each child.value = operator(root, a)
for each child: child.parent = root
for each child: child.operator = operator as a string
loop through all children and check to see what number you need to produce n with each operator, if that number is in the list of children
when you find something like that then you have paths back up the tree, use the following loop for both children (obviously a child with only i
i = 0
while child != root:
expression += “(“ + str(a) + child.operator
child = child.parent
expression += str(a)
for in range(i):
expression += “)”
then you combine the expressions and you have one possible solution to add up to n and you have one possible answer
store the solution in solutions with the key as the number of operators used and the value as the expression in string form
re_express(n, a, children, root, solutions)
As you can tell the big-O for that algorithm is garbage and it doesn't even give a guaranteed solution, so there must be a better way.
We can use a variation of Dijkstra's algorithm to find the result. However, we don't really have a graph. If we consider numbers as nodes of the graph, then edges would start at a pair of nodes and an operation and end at another number. But this is just a detail that does not prevent Dijkstra's idea.
The idea is the following: We start with y and explore more and more numbers that we can express using a set of pre-defined operations. For every number, we store how many operations we need to express it. If we find a number that we have already seen (but the previous expression takes more operations), we update the number's attributes (this is the path length in Dijktra's terms).
Let's do the example x = 9, y = 2.
Initially, we can represent 2 with zero operations. So, we put that in our number list:
2: 0 operations
From this list, we now need to find the number with the least number of operations. This is essential because it guarantees that we never need to visit this number again. So we take 2. We fix it and explore new numbers that we can express using 2 and all other fixed numbers. Right now, we only have 2, so we can express (using + - * /):
2: 0 operations, fixed
0: 1 operation (2 - 2)
1: 1 operation (2 / 2)
4: 1 operation (2 + 2 or 2 * 2)
On we go. Take the next number with the least number of operations (does not matter which one). I'll take 0. We can't really express new numbers with zero, so:
2: 0 operations, fixed
0: 1 operation (2 - 2), fixed
1: 1 operation (2 / 2)
4: 1 operation (2 + 2 or 2 * 2)
Now let's take 1. The number of operations for new numbers will be the sum of the input numbers' number of operations plus 1. So, using 1, we could
2 + 1 = 3 with 0 + 1 + 1 = 2 operations (2 + (2 / 2))
0 + 1 = 1 with 3 operations --> the existing number of operations for `0` is better, so we do not update
1 + 1 = 2 with 3 operations
2 - 1 = 1 with 2 operations
0 - 1 = -1 with 3 operations *new*
1 - 2 = -1 with 2 operations *update*
1 - 0 = 1 with 3 operations
1 - 1 = 0 with 3 operations
2 * 1 = 2 with 2 operations
0 * 1 = 0 with 3 operations
1 * 1 = 1 with 3 operations
2 / 1 = 2 with 2 operations
0 / 1 = 0 with 3 operations
1 / 2 = invalid if you only want to consider integers, use it otherwise
1 / 0 = invalid
1 / 1 = 1 with 3 operations
So, our list is now:
2: 0 operations, fixed
0: 1 operation (2 - 2), fixed
1: 1 operation (2 / 2), fixed
3: 2 operations (2 + 2/2)
4: 1 operation (2 + 2 or 2 * 2)
-1: 2 operations (2/2 - 2)
Go on and take 4 and so on. Once you've reached your target number x, you are done in the smallest possible way.
In pseudo code:
L = create a new list with pairs of numbers and their number of operations
put (y, 0) into the list
while there are unfixed entries in the list:
c = take the unfixed entry with the least number of operations
fix c
if c = x:
finish
for each available operation o:
for each fixed number f in L:
newNumber = o(c, f)
operations = c.numberOfOperations + f.numberOfOperations + 1
if newNumber not in L:
add (newNumber, operations) to L
else if operations < L[newNumber].numberOfOperations:
update L[newNumber].numberOfOperations = operations
repeat for o(f, c)
If you store the operation list with the numbers (or their predecessors), you can reconstruct the expression at the end.
Instead of using a simple list, a priority queue will make the retrieval of unfixed entries with the minimum number of operations fast.
Here is my code for this problem which I don't think is the fastest and the most optimal algorithm, but it should always find the best answer.
First, let's assume we don't have parentheses and solve the subproblem for finding the minimum number of operations to convert a to n with these operations ['+', '*', '/', '-']. For solving this problem we use BFS. First we define an equation class:
class equation:
def __init__(self, constant, level=0, equation_list=None):
self.constant = constant
if equation_list != None:
self.equation_list = equation_list
else:
self.equation_list = [constant]
self.level = level
def possible_results(self):
return recursive_possible_results(self.equation_list)
def get_child(self, operation):
child_equation_list = self.equation_list + [operation]
child_equation_list += [self.constant]
child_level = self.level + 1
return equation(self.constant, child_level, child_equation_list)
The constructor gets a constant which is the constant in our expressions (here is a) and a level which indicates the number of operations used in this equation, and an equation_list which is a list representation of equation expression. For the first node, ( root ) our level is 0, and our equation_list has only the constant.
Now let's calculate all possible ways to parentheses an equation. We use a recursive function which returns a list of all possible results and their expressions:
calculated_expr = {}
def is_operation(symbol):
return (symbol in operations)
def recursive_possible_results(equation_list):
results = []
if len(equation_list) == 1:
return [{'val': equation_list[0], 'expr': str(equation_list[0])}]
key = ''
for i in range(len(equation_list)):
if is_operation(equation_list[i]):
key += equation_list[i]
if key in calculated_expr.keys():
return calculated_expr[key]
for i in range(len(equation_list)):
current_symbol = equation_list[i]
if is_operation(current_symbol):
left_results = recursive_possible_results(equation_list[:i])
right_results = recursive_possible_results(equation_list[i+1:])
for left_res in left_results:
for right_res in right_results:
try:
res_val = eval(str(left_res['val']) + current_symbol + str(right_res['val']))
res_expr = '(' + left_res['expr'] + ')' + current_symbol + '(' + right_res['expr'] + ')'
results.append({'val': res_val, 'expr': res_expr})
except ZeroDivisionError:
pass
calculated_expr[key] = results
return results
(I think this is the part of the code that needs to be more optimized since we are calculating a bunch of equations more than once. Maybe a good dynamic programming algorithm ...)
For Breadth-First-Search we don't need to explore the whole tree from the root. For example for converting 2 to 197, we need at least 7 operations since our biggest number with 6 operations is 128 and is still less than 197. So, we can search the tree from level 7. Here is a code to create our first level's nodes (equations):
import math
import itertools
def create_first_level(n, constant):
level_exprs = []
level_number = int(math.log(n, constant)) - 1
level_operations = list(itertools.product(operations, repeat=level_number))
for opt_list in level_operations:
equation_list = [constant]
for opt in opt_list:
equation_list.append(opt)
equation_list.append(constant)
level_exprs.append(equation(constant, level_number, equation_list))
return level_exprs
In the end, we call our BFS and get the result:
def re_express(n, a):
visit = set()
queue = []
# root = equation(a)
# queue.append(root)
# Skip levels
queue = create_first_level(n, a)
while queue:
curr_node = queue.pop(0)
for operation in operations:
queue.append(curr_node.get_child(operation))
possible_results = curr_node.possible_results()
for pr in possible_results:
if pr['val'] == n:
print(pr['expr'])
print('Number of operations: %d' % curr_node.level)
queue = []
break
re_express(9, 2)
Here is the output:
(((2)+(2))*(2))+((2)/(2))
Number of operations: 4
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
I'm trying to maximize the Euler Totient function on Python given it can use large arbitrary numbers. The problem is that the program gets killed after some time so it doesn't reach the desired ratio. I have thought of increasing the starting number into a larger number, but I don't think it's prudent to do so. I'm trying to get a number when divided by the totient gets higher than 10. Essentially I'm trying to find a sparsely totient number that fits this criteria.
Here's my phi function:
def phi(n):
amount = 0
for k in range(1, n + 1):
if fractions.gcd(n, k) == 1:
amount += 1
return amount
The most likely candidates for high ratios of N/phi(N) are products of prime numbers. If you're just looking for one number with a ratio > 10, then you can generate primes and only check the product of primes up to the point where you get the desired ratio
def totientRatio(maxN,ratio=10):
primes = []
primeProd = 1
isPrime = [1]*(maxN+1)
p = 2
while p*p<=maxN:
if isPrime[p]:
isPrime[p*p::p] = [0]*len(range(p*p,maxN+1,p))
primes.append(p)
primeProd *= p
tot = primeProd
for f in primes:
tot -= tot//f
if primeProd/tot >= ratio:
return primeProd,primeProd/tot,len(primes)
p += 1 + (p&1)
output:
totientRatio(10**6)
16516447045902521732188973253623425320896207954043566485360902980990824644545340710198976591011245999110,
10.00371973209101,
55
This gives you the smallest number with that ratio. Multiples of that number will have the same ratio.
n = 16516447045902521732188973253623425320896207954043566485360902980990824644545340710198976591011245999110
n*2/totient(n*2) = 10.00371973209101
n*11*13/totient(n*11*13) = 10.00371973209101
No number will have a higher ratio until you reach the next product of primes (i.e. that number multiplied by the next prime).
n*263/totient(n*263) = 10.041901868473037
Removing a prime from the product affects the ratio by a proportion of (1-1/P).
For example if m = n/109, then m/phi(m) = n/phi(n) * (1-1/109)
(n//109) / totient(n//109) = 9.91194248684247
10.00371973209101 * (1-1/109) = 9.91194248684247
This should allow you to navigate the ratios efficiently and find the numbers that meed your need.
For example, to get a number with a ratio that is >= 10 but closer to 10, you can go to the next prime product(s) and remove one or more of the smaller primes to reduce the ratio. This can be done using combinations (from itertools) and will allow you to find very specific ratios:
m = n*263/241
m/totient(m) = 10.000234225865265
m = n*(263...839) / (7 * 61 * 109 * 137) # 839 is 146th prime
m/totient(m) = 10.000000079805726
I have a partial solution for you, but the results don't look good.. (this solution may not give you an answer with modern computer hardware (amount of ram is limiting currently)) I took an answer from this pcg challenge and modified it to spit out ratios of n/phi(n) up to a particular n
import numba as nb
import numpy as np
import time
n = int(2**31)
#nb.njit("i4[:](i4[:])", locals=dict(
n=nb.int32, i=nb.int32, j=nb.int32, q=nb.int32, f=nb.int32))
def summarum(phi):
#calculate phi(i) for i: 1 - n
#taken from <a>https://codegolf.stackexchange.com/a/26753/42652</a>
phi[1] = 1
i = 2
while i < n:
if phi[i] == 0:
phi[i] = i - 1
j = 2
while j * i < n:
if phi[j] != 0:
q = j
f = i - 1
while q % i == 0:
f *= i
q //= i
phi[i * j] = f * phi[q]
j += 1
i += 1
#divide each by n to get ratio n/phi(n)
i = 1
while i < n: #jit compiled while loop is faster than: for i in range(): blah blah blah
phi[i] = i//phi[i]
i += 1
return phi
if __name__ == "__main__":
s1 = time.time()
a = summarum(np.zeros(n, np.int32))
locations = np.where(a >= 10)
print(len(locations))
I only have enough ram on my work comp. to test about 0 < n < 10^8 and the largest ratio was about 6. You may or may not have any luck going up to larger n, although 10^8 already took several seconds (not sure what the overhead was... spyder's been acting strange lately)
p55# is a sparsely totient number satisfying the desired condition.
Furthermore, all subsequent primorial numbers are as well, because pn# / phi(pn#) is a strictly increasing sequence:
p1# / phi(p1#) is 2, which is positive. For n > 1, pn# / phi(pn#) is equal to pn-1#pn / phi(pn-1#pn), which, since pn and pn-1# are coprime, is equal to (pn-1# / phi(pn-1#)) * (pn/phi(pn)). We know pn > phi(pn) > 0 for all n, so pn/phi(pn) > 1. So we have that the sequence pn# / phi(pn#) is strictly increasing.
I do not believe these to be the only sparsely totient numbers satisfying your request, but I don't have an efficient way of generating the others coming to mind. Generating primorials, by comparison, amounts to generating the first n primes and multiplying the list together (whether by using functools.reduce(), math.prod() in 3.8+, or ye old for loop).
As for the general question of writing a phi(n) function, I would probably first find the prime factors of n, then use Euler's product formula for phi(n). As an aside, make sure to NOT use floating-point division. Even finding the prime factors of n by trial division should outperform computing gcd n times, but when working with large n, replacing this with an efficient prime factorization algorithm will pay dividends. Unless you want a good cross to die on, don't write your own. There's one in sympy that I'm aware of, and given the ubiquity of the problem, probably plenty of others around. Time as needed.
Speaking of timing, if this is still relevant enough to you (or a future reader) to want to time... definitely throw the previous answer in the mix as well.
I was curious if any of you could come up with a more streamline version of code to calculate Brown numbers. as of the moment, this code can do ~650! before it moves to a crawl. Brown Numbers are calculated thought the equation n! + 1 = m**(2) Where M is an integer
brownNum = 8
import math
def squareNum(n):
x = n // 2
seen = set([x])
while x * x != n:
x = (x + (n // x)) // 2
if x in seen: return False
seen.add(x)
return True
while True:
for i in range(math.factorial(brownNum)+1,math.factorial(brownNum)+2):
if squareNum(i) is True:
print("pass")
print(brownNum)
print(math.factorial(brownNum)+1)
break
else:
print(brownNum)
print(math.factorial(brownNum)+1)
brownNum = brownNum + 1
continue
break
print(input(" "))
Sorry, I don't understand the logic behind your code.
I don't understand why you calculate math.factorial(brownNum) 4 times with the same value of brownNum each time through the while True loop. And in the for loop:
for i in range(math.factorial(brownNum)+1,math.factorial(brownNum)+2):
i will only take on the value of math.factorial(brownNum)+1
Anyway, here's my Python 3 code for a brute force search of Brown numbers. It quickly finds the only 3 known pairs, and then proceeds to test all the other numbers under 1000 in around 1.8 seconds on this 2GHz 32 bit machine. After that point you can see it slowing down (it hits 2000 around the 20 second mark) but it will chug along happily until the factorials get too large for your machine to hold.
I print progress information to stderr so that it can be separated from the Brown_number pair output. Also, stderr doesn't require flushing when you don't print a newline, unlike stdout (at least, it doesn't on Linux).
import sys
# Calculate the integer square root of `m` using Newton's method.
# Returns r: r**2 <= m < (r+1)**2
def int_sqrt(m):
if m <= 0:
return 0
n = m << 2
r = n >> (n.bit_length() // 2)
while True:
d = (n // r - r) >> 1
r += d
if -1 <= d <= 1:
break
return r >> 1
# Search for Browns numbers
fac = i = 1
while True:
if i % 100 == 0:
print('\r', i, file=sys.stderr, end='')
fac *= i
n = fac + 1
r = int_sqrt(n)
if r*r == n:
print('\nFound', i, r)
i += 1
You might want to:
pre calculate your square numbers, instead of testing for them on the fly
pre calculate your factorial for each loop iteration num_fac = math.factorial(brownNum) instead of multiple calls
implement your own, memoized, factorial
that should let you run to the hard limits of your machine
one optimization i would make would be to implement a 'wrapper' function around math.factorial that caches previous values of factorial so that as your brownNum increases, factorial doesn't have as much work to do. this is known as 'memoization' in computer science.
edit: found another SO answer with similar intention: Python: Is math.factorial memoized?
You should also initialize the square root more closely to the root.
e = int(math.log(n,4))
x = n//2**e
Because of 4**e <= n <= 4**(e+1) the square root will be between x/2 and x which should yield quadratic convergence of the Heron formula from the first iteration on.