Thursday, 15 September 2011

Project Euler: problem 1

To be fairly honest (assuming there are degrees of honesty), I do know a little about math and programming but I don't know much math or any programming. I've loved math for a long time, but started to learn and understand fairly recently. So during the process of learning and understanding math and a little bit of programming, Shreyes and I thought of sharing our procedures. Most of these procedures aren't the most elegant solutions and at times are plain clumsy and inefficient. We plan to improve our programming skills as we go along.

We have recently started with Project Euler problems and will be posting some of the methods that we have used to arrive at a solution for each of the problems. We know only one language, R and hence our solutions are written in R.

So let's start with problem 1

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.

I tried two approaches to solve this problem and have detailed both of them below. By the time I was through with the problem, I found another approach.

First, let's see the one that I thought was quite efficient.

# Approach 1

# Create an empty vector of desired length where the results of the division will be stored
x.1 <- rep(NA, 999) 
#NA is replicated 999 times

# For each integer from 1 to 999 (we want numbers below 1000), divide the integer # by either 3 or 5 and take the modulus. 
# If the integer, say "i" is completely divisible by either 3 or 5, assign  that value to the ith element of vector x; otherwise assign i'th value of x to equal to zero
for (i in 1:999){
                if (i %% 3 == 0 || i %% 5 == 0) {x.1[i] <- i} else {x.1[i] <- 0}
# "%%" is the modulus function, "||" is the symbol for the "or" command, x.1[i] calls the ith element of vector x.1

# Take all the non-zero values of x, i.e. those values for which the integer was perfectly divisible by either 3 or 5 and assign it to a separate vector
y.1 <- x.1[x.1 != 0]
# This assigns all the nonzero rows of vector x.1 to a vector y.1

# Take a summation of these values and this is the desired output.
# "sum" finds the sum of all the elements of vector y.1

Answer: 233168

Also, just to make sure that there is no confusion, the ".1" in x.1 and y.1 does not denote anything special, it is merely an assigning convention indicating that the variables were created for the first approach.

# Approach 2

# Take numbers from 1 to 333 and multiply each by 3 to get multiples of 3.
# We only take numbers till 333 because we have to find the sum of multiples of 3 (and 5) that are less than 1000.
x.2 <- 0
for (i in 1:333){x.2[i] <- i*3}
# head shows the first few rows of the object

# For multiples of 5, we take numbers till 199 and the last multiple of 5 below 1000 comes to be 995
y.2 <- 0
for (j in 1:199){y.2[j] <- j*5}

# 15 is a common multiple of 3 and 5, and hence it will get included twice - once when we add the numbers that are multiples of 3 and once when we add numbers that are multiples of 5. So we need to subtract these 15 and its multiples.
z.2 <- 0
for (k in 1:66){z.2[k] <- k*15}

# Final sum
sum(x.2) + sum(y.2) - sum(z.2)

Answer: 233168

There is another approach, which uses the funda of arithmetic progressions. Let's see if you can figure that out. 


  1. There is another approach without using loops.

    problem1 = function(n1,p1,p2){
    multp1 = seq(0,n1-1,by=p1)
    multp2 = seq(0,n1-1,by=p2)

    multips = c(multp1,multp2)

    #n1 for the upper bound 1000
    # p1 and p1 for the multiples, 3 and 5


  2. I see...

    Yes, the concept of using Arithmetic Progressions is a much "neater" way to do it.

    I really need to work on my function building skills in R. :)

  3. x <- 1:999
    sum(x[x%%3 == 0 | x%%5 == 0])

  4. 999*334/2 + 995*200/2 - 990*67/2 = 233168