Project Euler 12

The sequence of triangle numbers is generated by adding the natural numbers. 
So the 7th triangle number would be 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?
三角数の数列は自然数を足すことで得られます。
7番目の三角数は1+2+3+4+5+6+7+8+9+10=28です。
最初の10個は以下のようになっています。

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

最初の7つの三角数の因数をリストすると以下のようになります。

 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

28は5個以上の因数を持つ最初の三角数であることがわかります。
500個以上の因数を持つ最初の三角数の数はいくらでしょう。

Mathematica

j = 1;
sLength = 1;
 While[sLength < 500,
   s = Sum[i, {i, j}];
   sLength = Length[Divisors[s]];
   j++
   ];
s

これで一応答えは求められますが、割と時間がかかってしまいます。
AbsoluteTiming関数によると17.14秒という結果になりました。
ここで一番時間がかかっているのはSumの部分です。例えば j=10000 ならば10000回足しているのですから当然です。
さて、三角数は n(n+1)/2 で求めることができるので、以下のように置き換えてやります。

j = 1;
sLength = 1;
s = 1;
 While[sLength < 500,
   s = j (j + 1)/2;
   sLength = Length[Divisors[s]];
   j++
   ];
s

これによって計算時間は0.28秒まで減らせました。
ここで注意(というか僕が引っかかった)のは、sの計算で「/2」を用いたことです。
「*0.5」でももちろん計算上は同じなのですが、これを行うと s は浮動小数点型となります。
Divisors関数の引数は整数でなくてはいけませんから、「*0.5」を使うならば以下のようにしましょう。
IntegerPart関数を1つはさんでいますが、意外にも計算時間は変わりませんでした。

j = 1;
sLength = 1;
s = 1;
 While[sLength < 500,
   s = IntegerPart[j (j + 1) *0.5];
   sLength = Length[Divisors[s]];
   j++
   ];
s

C/C++

#include <iostream>
using namespace std;

// nの約数の個数を返す。
int divisor_count(int n){
	int j,c = 1;
	for(int i=2 ; i*i <= n ; i++, c *= j){
		for(j=1 ; !(n%i); j++) n /= i;
	}
	return (1<n) ? c*2 : c;
}

int main(){
	const int DIVMAX = 500;
	int i=2, n, count;

	// i番目の三角数が n
	while(1){
		n = i*(i+1)/2;
		count = divisor_count(n);
		if(count>=DIVMAX) break;
		i++;
	}
	cout << i << "th " << n << " -> " << count << endl;
	return 0;
}

最初は適当に約数の個数を返す関数を自分で書いてたのですが、とにかく遅い。
ググったらこのページに辿り着きました。
速くていいね!