A new day, new Project Euler challenge, who would guess that after problem No. 11 comes problem No. 12:

The sequence of triangle numbers is generated by adding the natural numbers. So the

`7`

triangle number would be^{th}`1 + 2 + 3 + 4 + 5 + 6 + 7 = 28`

. The first ten terms would be:`1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...`

Let us list the factors of the first seven triangle numbers:

`1: 1`

`3: 1,3`

`6: 1,2,3,6`

`10: 1,2,5,10`

`15: 1,3,5,15`

`21: 1,3,7,21`

`28: 1,2,4,7,14,28`

We can see that 28 is the first triangle number to have over five divisors.

What is the value of the first triangle number to have over five hundred divisors?

So, we will need a function to count divisors of a number, that's for sure. If we look in detail on the method to get a number of all the positive divisors of a value, we soon find out that it can be broken into getting the prime factors of a number and multiplying their powers increased by one. We've already done a similar thing with the `primeFactorsPow`

function. This time there's no need to keep an array of the values as we only work with individual numbers. Also, as the powers are to be increased by one, the `pow`

variable is initialized with a value of `1L`

instead of `0L`

:

`fn countDivisors nr count:1 =`

`(`

`if isEven nr do`

`(`

`local pow = 1L`

`do (nr /= 2L; pow += 1) while isEven nr`

`count *= pow`

`)`

`local rootN = nr^0.5`

`for i = 3 to rootN by 2`

`where mod nr i == 0 do`

`(`

`local pow = 1L`

`do (nr /= i; pow += 1) while mod nr i == 0`

`count *= pow`

`)`

`if nr > 1 do`

`count *= 2`

`count`

`)`

But wait, do we really have to count the divisors for each and every number? Let's have a look at what we are dealing with, what are the properties of the triangle numbers that we could use? The infographic on the right says that `T`

equals _{n}`(n × (n+1))/2`

. The proof here is quite simple, when you take the triangle that represents the number `T`

, mirror it and put them together, this is what you will get _{n}`(for n = 4)`

:

`n × (n+1)`

elements, and as it is double the size we need, by dividing it by two, we get our result. So it's always a multiplication and we could use it to our advantage as *. The difference here is that we have*

the total number of positive divisors of`n`

is a multiplicative function`d(n)`

, e.g.`d(42) = 8 = 2 × 2 × 2 = d(2) × d(3) × d(7)`

`(n × (n+1))/2`

and not just `n × (n+1)`

. But there's always one of those values that's even, as they differ exactly by one, so we can just take the even one (once again using the `isEven`

function) and divide it by two:
To wrap it all together in a nice package we only have to write the for loop (I've started with seven here as the biggest triangle number in the description was the seventh in order) and exit with`fn countTriangleDivisors nr =`

`(`

`if isEven nr then`

`(countDivisors (nr/2)) * (countDivisors (nr+1))`

`else (countDivisors nr) * (countDivisors ((nr+1)/2))`

`)`

`nthTriangle`

:
`(`

`local inf = 1.0/0.`

`fn isEven nr = bit.and 1L nr == 0`

`fn countDivisors nr count:1 =`

`(`

`if isEven nr do`

`(`

`local pow = 1L`

`do (nr /= 2L; pow += 1) while isEven nr`

`count *= pow`

`)`

`local rootN = nr^0.5`

`for i = 3 to rootN by 2`

`where mod nr i == 0 do`

`(`

`local pow = 1L`

`do (nr /= i; pow += 1) while mod nr i == 0`

`count *= pow`

`)`

`if nr > 1 do`

`count *= 2`

`count`

`)`

`fn countTriangleDivisors nr =`

`(`

`if isEven nr then`

`(countDivisors (nr/2)) * (countDivisors (nr+1))`

`else (countDivisors nr) * (countDivisors ((nr+1)/2))`

`)`

`fn nthTriangle n = (n^2+n)/2`

`for i = 7 to inf`

`where countTriangleDivisors i > 500 do`

`exit with nthTriangle (integer64 i)`

`)`

It could use some work to make the preformance better, though. Note that there would be no significant speed gain (if any) if we would store previous results of our iterative `countDivisors`

function but it could be an important factor if using recursive version of the same function.

DISCLAIMER: All scripts and snippets are provided as is under Creative Commons Zero (public domain, no restrictions) license. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.

## This Post needs Your Comment!

Leave a Comment