Paul Waring

Freelance C Developer based in Manchester, UK

Project Euler problem 12

Highly Divisible Triangular Number

Find the first triangle number with over 500 factors.

Solution

Generating a list of triangular numbers is trivial, as we start from 1 and add a step of 2, incrementing the step each time. The first 1mn can be generated with:

int triangle_number = 0;
int step = 0;

for (triangle_number = 1, step = 2; triangle_number < 1000000 triangle_number += step, step++) {
    printf("%d\n", triangle_number);
}

We also need a way of counting the factors for a given number. The simplest way would be to attempt to divide n by every number from 1 to n. However, every factor f must have a paired factor f', such that f x f' = n. This means that we only need to divide n by every number from 1 to the square root of n, and add 2 to the factor count each time there is no remainder. The only edge case we have to consider is when f = f', which will only happen when f is the square root of n. In this case we only count the factor once.

We can write a short function to do this:

int count_factors(int factorise) {
    int factor_count = 0;
    int possible_factor = 0;
    int other_factor = 0;
    int upper_bound = (int) floor(sqrt(factorise));

    for (possible_factor = 1; possible_factor <= upper_bound; possible_factor++) {
        if (factorise % possible_factor == 0) {
            factor_count++;

            other_factor = factorise / possible_factor;
            if (other_factor != possible_factor) {
                factor_count++;
            }
        }
    }

    return factor_count;
}

The only line worthy of comment is:

int upper_bound = (int) floor(sqrt(factorise));

This will cause a warning to be emitted if -Wbad-function-cast is used, either explicitly or via -Weverything (it is not included in -Wall or -Wextra). This is because there may be numbers that can be stored in a double but not an int, and therefore the cast is potentially unsafe.

The full solution is:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdbool.h>

#define FACTOR_COUNT_TARGET 500

static int count_factors(int factorise) {
    int factor_count = 0;
    int possible_factor = 0;
    int other_factor = 0;
    int upper_bound = (int) floor(sqrt(factorise));

    for (possible_factor = 1; possible_factor <= upper_bound; possible_factor++) {
        if (factorise % possible_factor == 0) {
            factor_count++;

            other_factor = factorise / possible_factor;
            if (other_factor != possible_factor) {
                factor_count++;
            }
        }
    }

    return factor_count;
}

int main() {
    int triangle_number = 0;
    int step = 0;
    bool target_met = false;

    for (triangle_number = 1, step = 2; !target_met; triangle_number += step, step++) {
        if (count_factors(triangle_number) > FACTOR_COUNT_TARGET) {
            target_met = true;
            printf("%d\n", triangle_number);
        }
    }

    return EXIT_SUCCESS;
}        

Note that the count_factors function has been made static to indicate that it is not called from outside this compilation unit.