Christopher Tobin

Project Euler Problem 1 Solution in C#

Christopher Tobin
Christopher Tobin

February 07, 2020

On this page is the solution for Problem 1 of Project Euler. If you want just analysis about this problem, check it out here. Turn back now if you do not want the solution.

If you want a refresher about what is being asked:

Multiples of 3 and 5

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.

Test Driven Development

The minds behind Project Euler have been so thoughtful as to grace us with an example. This allows us to begin our journey by writing a unit test to account for the case described in the example. The test will pass 10 as the input parameter to some function and will expect a value of 23 to be returned.

[TestMethod]
public void Problem1_Example()
{
    // Arrange
    const int input = 10;

    // Act
    var result = Problem1.Solve(input);

    // Assert
    Assert.AreEqual(23, result);
}

Now that we have our test written for the example case, we’ll need to write some code to make the test pass. First we’ll need a class and a method. I’ll be making both the class and the method static because we won’t have a need to ever create an instance of this class.

public static class Program1
{
    public static int Solve(int input)
    {
        // TODO: implementation here...
    }
}

We could of course cheat and do something real cheesy. After all, the whole point of test driven development is to write the simplest solution to satisfy the test right?

public static int Solve(int input)
{
    return 23;
}

When we run the test it passes! That’s good right? Of course not. This is complete crap. If we pass a value of 1000 into this method it will still return a value of 23, which is most definitely not correct. We can add an additional test to verify that when the method input is 1000, we don’t receive the value of 23 back.

[TestMethod]
public void Problem1_Answer()
{
    // Arrange
    const int input = 1000;

    // Act
    var result = Problem1.Solve(input);

    // Assert
    Assert.AreNotEqual(23, result);
}

This test fails like we expect it to. We don’t know the actual value to expect back yet so we can’t assert anything else at this point. These tests will provide a good foundation for moving forward with solving the problem.

Solving the Problem

A simple implementation for the solution to this problem is to use a loop to iterate over all of the numbers between 1 and whatever the value of the input variable is. The most common choices for loops are a for loop and a while loop. Either would work in this scenario but a for loop is the best choice here because there is a defined number of iterations. When we know that the loop will iterate for a defined amount of times, a for loop is the obvious choice. We’ll go through the loop up to the number specified in the input variable.

public static int Solve(int input)
{
    for(var number = 1; number < input; number++)
    {
        // implementation...
    }
}

Now that we have the loop, we need to fill it with stuff. We’ll first check if the number is divisible by 3. We’ll also need to keep track of all of the numbers that are divisible by either 3 or 5 so that we can add them up once we get to the end.

public static int Solve(int input)
{
    var numbersDivisibleBy3or5 = new List<int>();
    for (var number = 1; number < input; number++)
    {
        var isNumberDivisibleBy3or5 = false;
        if (number % 3 == 0)
        {
            // This number is divisible by 3!
            isNumberDivisibleBy3or5 = true;
        }
        else
        {
            // This number is not divisible by 3!
            isNumberDivisibleBy3or5 = false;
        }

        if (isNumberDivisibleBy3or5)
        {
            numbersDivisibleBy3or5.Add(number);
        }
    }
}

There are a few things going on here:

  • A list of int has been added so that we can keep track of the numbers divisible by either 3 or 5
  • We execute an if statement to check if the number is divisible by 3
    • We do this by using the mod operator (%)
    • The mod operator will output the remainder. When this expression outputs 0, we know that the number is divisible by 3.
    • More info about this operator can be found on the Microsoft Documentation site.
  • Whenever a number is divisible by 3, a local boolean variable isNumberDivisibleBy3or5 is set to true
  • When a number is not divisible by 3, we set isNumberDivisibleBy3or5 to false

That seems like a good start right? Now that we have all of the numbers that are divisible by 3, we can proceed to determining the numbers divisible by 5.

public static int Solve(int input)
{
    var numbersDivisibleBy3or5 = new List<int>();
    for (var number = 1; number < input; number++)
    {
        var isNumberDivisibleBy3or5 = false;

        if (number % 3 == 0)
        {
            // This number is divisible by 3!
            isNumberDivisibleBy3or5 = true;
        }
        else
        {
            // This number is not divisible by 3!
            isNumberDivisibleBy3or5 = false;
        }

        if (number % 5 == 0)
        {
            // This number is divisible by 5!
            isNumberDivisibleBy3or5 = true;
        }
        else
        {
            // This number is not divisible by 5!
            isNumberDivisibleBy3or5 = false;
        }

        if (isNumberDivisibleBy3or5)
        {
            numbersDivisibleBy3or5.Add(number);
        }
    }
}

Easy peasy! We should now have all of the numbers divisible by either 3 or 5 in a list. All we need to do is add them all up and return the result. But how can we add all of the numbers in the list? One way would be to loop through this list and add each number to the previous one like so:

var total = 0;
foreach (var divisibleNumber in numbersDivisibleBy3or5)
{
    total += divisibleNumber;
}

return total;

Bugs Everywhere

This should work right? If we run the test covering the example we actually see something unexpected - a failed test. Instead of the expected value of 23, we’re getting a value of 5. How on Earth is that happening??

There’s actually a bug in the code. Any time a number is not divisible by either 3 or 5, the isNumberDivisibleBy3or5 variable is being set to false. That’s correct behavior right? Well, not necessarily.

When a number is divisible by 3, isNumberDivisibleBy3or5 is set to true, which is what we expect. However, when we check if this same number is also divisible by 5, we are running into some problems when the number is not divisible by 5. Whenever a number is not divisible by 5, isNumberDivisibleBy3or5 is being set to false. Even if that number was already divisible by 3!

This is pretty simple to fix. All we need to do is remove the else condition when evaluating if a number is divisible by 3 or 5.

for (var number = 1; number < input; number++)
{
    var isNumberDivisibleBy3or5 = false;

    if (number % 3 == 0)
    {
        // This number is divisible by 3!
        isNumberDivisibleBy3or5 = true;
    }

    if (number % 5 == 0)
    {
        // This number is divisible by 5!
        isNumberDivisibleBy3or5 = true;
    }

    if (isNumberDivisibleBy3or5)
    {
        numbersDivisibleBy3or5.Add(number);
    }
}

This fixes the bug and now the test for the example case passes!

Make it Better

Now that we’ve made a working solution, we can attempt to make it better. There are a few optimizations that can be made. The great thing about doing this is that we already have passing unit tests. After we make changes we can re-run the test to ensure we haven’t broken anything.

Unnecessary Looping

We’re currently doing some unnecessary looping at the end of the method to return the sum of all of the numbers divisible by 3 or 5. We can optimize this by keeping a running total of the sum of all numbers divisible by 3 or 5 as we go instead of storing them in a temporary list.

public static int Solve(int input)
{
    var sum = 0;
    for (var number = 1; number < input; number++)
    {
        if (number % 3 == 0)
        {
            // This number is divisible by 3!
            sum += number;
        }

        if (number % 5 == 0)
        {
            // This number is divisible by 5!
            sum += number;
        }
    }

    return sum;
}

Multiple if Statements

We have 2 separate if statements at the moment: one to see if the number is divisible by 3 and a different one to see if the number is divisible by 5. We can combine these into one if statement with the OR (||) operator to make it a bit cleaner.

public static int Solve(int input)
{
    var sum = 0;
    for (var number = 1; number < input; number++)
    {
        if (number % 3 == 0 || number % 5 == 0)
        {
            // This number is divisible by 3 or by 5!
            sum += number;
        }
    }

    return sum;
}