4

I've been learning Python 2.5.4 and I have the following problem to solve:

"Write a program that computes the sum of the logarithms of all the primes from 2 to some number n, and print out the sum of the logs of the primes, the number n, and the ratio of these two quantities. Test this for different values of n."

This is what I have so far:

from math import *
n = raw_input('This is a logarithm ratio tester. Which number do you want to test? ')
for x in range(2,n):                            #picks numbers to test
    for divisor in range(2, 1+int(sqrt(x+1))):
        if x%divisor == 0:                      #checks if x is prime
            log(x)                              #computes log of prime

Unfortunately I'm not sure how to implement a function for summing all the logs. I would imagine that once I have that, I just need to conclude the program with:

print 'Sum of the logs of the primes is',logsum
print 'n =',n
print 'Ratio of sum to n is',logsum/n

Or some variant. But what would be a good way to obtain what I've labeled logsum? Please note I have been studying programming for no more than a week, I know very few statements/functions by heart, and I am not a mathematician. When in doubt, assume I'm an idiot. Thanks!

devonjones
  • 75
  • 2
  • 6
  • 4
    Quick aside - if you don't have to support a legacy codebase running on Python 2.5 or something like that, you should _really_ upgrade to either 2.7 or 3.3/3.4. – senshin Feb 16 '14 at 23:35
  • I would love to upgrade, but the course I'm doing is MIT's OpenCourseWare program for Intro to Programming, and while it's a good course so far, it was made in 2008. The problem sets expect me to be using IDLE for Python 2.5. I plan to upgrade as soon as I finish learning these basics. ;) – devonjones Feb 17 '14 at 08:48

3 Answers3

4

I would wrap some of your code in functions, and fix your definition of prime:

def isprime(x):
  for j in range(2,1 + int(sqrt(x - 1))):
    if x%j == 0:
      return False
  return True

def primes(n):
    return [j for j in range(2, n) if isprime(n)]

logsum = 0
for p in primes(n):
    logsum += log(p)
colcarroll
  • 3,632
  • 17
  • 25
  • If you keep an explicit total instead of using `sum()` you can print results for various `n` without having to start all over again. – John La Rooy Feb 17 '14 at 00:13
3

You should check to see if the number is prime before calculating its log and then add the value of log(x) to a variable logsum like this:

from math import *
logsum = 0
n = raw_input('This is a logarithm ratio tester. Which number do you want to test? ')
for x in range(2,n):                            #picks numbers to test
    isprime = True
    for divisor in range(2, 1+int(sqrt(x+1))):
        if x%divisor == 0:                      #checks if x is prime
            isprime = False                                  #computes log of prime
            break
    if isprime:
        logsum += log(x)

Also, since you're checking a lot of values, maybe implementing The Sieve of Eratosthenes would be a nice way to continue learning.

EDIT: Using Juri Robl's suggestion, the code could be simplified to:

from math import *
logsum = 0
n = raw_input('This is a logarithm ratio tester. Which number do you want to test? ')
for x in range(2,n):                            #picks numbers to test
    for divisor in range(2, 1+int(sqrt(x+1))):
        if x%divisor == 0:                      #checks if x is prime
            break
    else:
        logsum += log(x)
Vlad Schnakovszki
  • 8,434
  • 6
  • 80
  • 114
  • 2
    You could use the `for...else` construct instead of the `isprime` bool. – Juri Robl Feb 17 '14 at 00:02
  • I don't use Python much so wasn't aware of this construct. Thanks for telling me about it. Learning something new everyday :) – Vlad Schnakovszki Feb 17 '14 at 00:03
  • This was a very helpful answer, thank you; it didn't introduce anything that I didn't already know how to do, but it filled in the gap in logic that I was having for writing the program as a whole. I'm having one new problem now, though: when I run the program and I've put in a number for n after it's requested, I get the following error. `for x in range(2,n): TypeError: range() integer end argument expected, got str.` – devonjones Feb 17 '14 at 08:59
  • Oh, and I thought of using the Sieve in this, but so far I've been trying to stick to math that I recollect clearly from high school. I'm afraid of coding things I don't conceptually understand, lol – devonjones Feb 17 '14 at 09:03
  • 1
    Never mind the above. I realized the raw_input function needed to be nested inside int() to avoid the type error. Now I'm all set. Thanks everyone! – devonjones Feb 17 '14 at 20:45
1

Notice that log(2) + log(3) + ... + log(n) = log(2*3*...*n)

You could then just use the Sieve of Eratosthenes to obtain a list of primes, multiply them together, and then take the logarithm of that product.

import math
import operator

def filter_primes(alist, newlist):
    for x in alist[1:]:
        if x%alist[0] != 0:
            newlist.append(x)
    return newlist

n = int(raw_input('This is a logarithm ratio tester. Which number do you want to test?'))
alist = range(2, n)
sieve_list = []
primes = [2]

while alist[0] < math.sqrt(n):
    a = filter_primes(alist, sieve_list)
    primes.append(a[0])
    alist = sieve_list
    sieve_list = []
for j in alist[1:]: primes.append(j)

product = reduce(lambda x, y: x*y, primes)
ans = math.log(product)

print 'The sum of the logs is: %d \nn is: %d \nThe ratio of these two quantities is: %s' %   (ans, n, float(ans/n))
o-90
  • 17,045
  • 10
  • 39
  • 63