Why doesn't this Sage program work properly (Project Euler 23)? - python

This is my solution to problem 23 of Project Euler, which is:
"A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers."
I have written this code, but for some reason it gives me 4190404 which is, according to the Project Euler website is incorrect.
import numpy
def lowfactor(n):
factors = [i for i in xrange(2, ceil(sqrt(n))) if n % i == 0]
return list(numpy.unique(factors))
def factor(n):
low = lowfactor(n)
factors = [n / i for i in low]
factors.reverse()
factors = factors + low
return factors
def isAbundant(n):
factors = factor(n)
factorSum = sum(factors)
return factorSum > n
abundants = [i for i in xrange(28124) if isAbundant(i)]
sums = map(lambda n: False, range(28124))
for a in xrange(0, len(abundants)):
for b in xrange(a, len(abundants)):
if (abundants[a] + abundants[b]) < 28124:
sums[abundants[a] + abundants[b]] = True
notsums = []
for i in xrange(28124):
if not sums[i]:
notsums.append(i)
sumofnotsums = sum(notsums)
print(sumofnotsums)

You'll see the problem if you calculate factor(28) and compare your result to answer given by Euler.

Related

Trying to find sum of digits between two numbers

Trying to figure out how to find the sum of digits between two numbers(including those numbers) using a function in python.
I tried recursion for each individual argument and then subtracted them to compensate for the numbers in between. Then I added these two and got my sum, which is incorrect for every argument unless the digits are below 10. Not sure of the proper way to approach this problem, please help.
def sum_digits(a, b):
"""sum of digits between two numbers"""
sum = 0
ones = a - b
if ones < 0:
ones = ones * -1
if a >= 10 and b >= 10:
sum += ones
while a > 0 and b > 0:
d = a % 10 + b % 10
a = a // 10
b = b // 10
sum += d
return sum
def sum_digits(a, b):
sum = 0
for i in range(a,b+1):
for e in (str(i)):
sum += int(e)
return sum
print(sum_digits(17, 20))
Does this work ?
this works basically by getting the numbers within a range. Now since endrange is usually one less, I manually add a 1 to the endrange
startNumber = 1
endNumber = 5
total = 0;
for i in range(startNumber,endNumber+1):
print(i)
total += i
print total
Thanks
Just sum the digit sum for every number from the first argument to the last. For more ways to do each digit sum, see Sum the digits of a number - python
def sum_digits(a, b):
total = 0
for number in range(a,b+1):
total += sum(int(digit) for digit in str(number))
return total
Here you go:
def sum_digits(a, b):
sum = 0
for i in range(a, b + 1):
number = i
while (number > 0):
sum += number % 10
number = number // 10
return sum
print(sum_digits(17, 20))
My approach:
def sum_of_products(lst, s, f):
result = 0
for i, item in enumerate(range(s, f+1)):
lst[i] = list(map(int, str(item)))
result += sum(lst[i])
return result
lst = [x for x in range(0, 10)]
x = sum_of_products(lst, 14, 20)
print(x)
My 2 cents would to point out that there should be a closed-form formula that doesn't involve looping trough the whole range.
For example, we know that the sum of n numbers is
n*(n-1)/2
and for the sum of digits 0 to 9 it is 45 == 9*10/2
01
02
03
04
05
06
07
08
09
then it becomes a bit more complicated for the next 10 numbers:
10
11
12
13
14
15
16
17
18
19
the sum is 10 times the tens(decades) plus 45.
and then we could have:
for 00..09 we have 0*10+45
for 10..19 we have 1*10+45
for 20..29 we have 2*10+45
...
for d0..d9 we have d*10+45
I am too lazy to derive the good formula myself, therefore I Googled it. And below is what I have found:
The formula is simple if we know before hand the number of digits. For example, as per https://oeis.org/A007953 , if the number of n is less than 100 then the closed-form formula is:
For n < 100 equal to (floor(n/10) + n mod 10)
For an arbitrarily large number there is a sample code here: https://www.geeksforgeeks.org/count-sum-of-digits-in-numbers-from-1-to-n/
dsum(10**d - 1) = dsum(10**(d-1) - 1) * 10 + 45*10**(d-1)
to compute the digit sum of a range just find the difference
dsum(b) - dsum(a)

Optimizing Totient function

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.

Euler Project 47 finding all numbers contaning 4 factors

I first create a list of 10^6 false values and what I want to do is to iterate True over the interval for all numbers containing 4 distinct prime factors.
What that means is that the number 2 * 2 * 3 * 5 * 7 is a number containing 4 distinct prime numbers.
I really have no clue how to create the numbers, I don't even know how to think of the it. I want to have 4 different kinds of numbers but in all possible different amounts. Code as far:
""" Pre do prime list """
sieve = [True] * 1000
sieve[0] = sieve[1] = False
def primes(sieve, x):
for i in range(x+x, len(sieve), x):
sieve[i] = False
for x in range(2, int(len(sieve) ** 0.5) + 1):
primes(sieve, x)
PRIMES = list((x for x in range(2, len(sieve)) if sieve[x]))
""" Main """
Numbers = [False] * 10 ** 6
Factors = PRIMES[0] * PRIMES[1] * PRIMES[2] * PRIMES[3]
Numbers[Factors] = True
for prime in PRIMES:
for prime in PRIMES[1:]:
for prime in PRIMES[2:]:
for prime in PRIMES[3:]:
I think the easiest way is to keep track of how many prime factors you have found for each number. You can perform the Sieve of Eratosthenes, but instead of marking multiples of a prime as composite, increment the count of primes dividing them. Make sure that you use an unoptimized loop: Once you choose the prime p, increment the count of primes dividing p, 2*p, 3*p etc. instead of marking p^2, p^2+2*p, etc. composite.
Another possibility is to record the smallest prime factor of each number as you perform the Sieve of Eratosthenes. This lets you find the prime factorization recursively, and you can check which of these have exactly 4 prime factors.
could you do it the other way round: get a list of primes up to root(N) then generate products that are less than N. Something like:
res = {}
for i in range(n):
for j in range(i,n):
for k in range(j,n):
for m in range(k,n):
prod = p[i] * p[j] * p[k] * p[m]
if prod < N:
res[prod] = [p[i], p[j], p[k], p[m]]
ed. just noticed distinct so you would have to put each p[] ** u and iterate each over a suitable number with another four nested loops! Probably still faster to do it this way round.
PPS after a little thought, the above method will be significantly slower than just using the modified sieve as suggested by Douglas Zare. By the time I get to 10**6 my first suggestion takes minutes but the modified sieve is less than 10s
class Numb(object):
def __init__(self):
self.is_prime = True
self.pf = []
def tick(self, factor):
self.is_prime = False
self.pf.append(factor)
N = 1000000
sieve = [Numb() for i in range(N)]
sieve[0].is_prime = sieve[1].is_prime = False
def primes(sieve, x):
for i in range(x + x, len(sieve), x):
sieve[i].tick(x)
for x in range(2, int(len(sieve) ** 0.5) + 1):
if sieve[x].is_prime:
primes(sieve, x)
I continued doing something like this, before trying out sieve method.. And in the end realising that I should use an search algorithm that finds two odd number with 4 distinct factors which differ by 2 and try the number in-between and the number before and after. if this condition is meet the problem is solved.
It's actually falls back on the same problem as stated in post but through some number-theory magic reduces to just finding numbers with no multiples of factors where question conditions is meet.
Factors = list([0, 0, 1, 1, 2, 1, 2, 1, 3, 2]) + [0] * 5 * 10 ** 5
for prime in PRIMES:
Factors[prime] = 1
for number in range(10, 5 * 10 ** 5):
if Factors[number] == 1:
continue
for prime in PRIMES:
if number % prime == 0:
Factors[number] = Factors[prime] + Factors[number // prime]
break

Finding the largest power of 2?

This is the code I created to find the largest power of 2 factor. I do not think that this is 100% correct because I keep getting 2 as the answer. I need some help figuring this out. I am completely new at programming.
MY CODE:
def largestPowerOfTwoThatIsAFactorOf(num):
factor = 2
while not(num > 0):
factor = factor + 1
return factor
print(largestPowerOfTwoThatIsAFactorOf(4))
print(largestPowerOfTwoThatIsAFactorOf(15))
print(largestPowerOfTwoThatIsAFactorOf(120))
#For any odd integer, largest power of 2 that’s a factor is 1.
This is an interesting and useful function, fit to deal with FFT, to perform Signal Processing and Analysis once FFT is a square matrix with "power of two" dimensions... understanding that a power of two is the result of two elevated to some power, and that there are infinite powers of two greater than n, a better name to the function should be minimum power of two greater than n - we just use it to dimension a collection of signal data to submit it to FFT filter. There follows two options, named minpowof2 and the maxpowof2...
def minpowof2(n):
'''Minimun Power of Two Greater Than n'''
f = 1
if n < 2: return 'try n greater or iqual to 2'
while n > 2:
n /= 2
f += 1
return 2**f
def maxpowof2(n):
'''Maximum Power of Two Lower than n'''
return int(minpot2(n)/2)
def largestPowerOfTwoThatIsAFactorOf(num):
if num % 2 != 0: return 1
factor = 0
while num % 2 == 0:
num /= 2
factor += 1
return 2 ** factor
## or return factor; as per your requirement
You need to update num inside the loop. Also, you cna optimize the code a little by checking whether the input was odd or not in the first statement.

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