12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- (*
- Amicable numbers
- Problem 21
- Let d(n) be defined as the sum of proper divisors of n (numbers less
- than n which divide evenly into n). If d(a) = b and d(b) = a, where a
- ≠ b, then a and b are an amicable pair and each of a and b are called
- amicable numbers.
- For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20,
- 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284
- are 1, 2, 4, 71 and 142; so d(284) = 220.
- Evaluate the sum of all the amicable numbers under 10000.
- *)
- fun print_int_list nil = print ""
- | print_int_list (num::nums) =
- let
- val _ = print (String.concat [(Int.toString num), "\n"]);
- in
- print_int_list nums
- end;
- fun sum nil = 0
- | sum lst = foldl op+ 0 lst;
- fun is_divisor num factor =
- (num mod factor) = 0;
- fun divisors num =
- let
- fun iter 1 factors = 1 :: factors
- | iter 0 factors = nil
- | iter n factors =
- if is_divisor num n
- then iter (n - 1) (n :: factors)
- else iter (n - 1) factors;
- in
- iter (num div 2) nil
- end;
- fun sum_divisors num =
- sum (divisors num);
- fun is_amicable num =
- let
- val divisor_sum = sum_divisors num;
- in
- (num = (sum_divisors divisor_sum)
- andalso
- not (num = divisor_sum))
- end;
- fun calculate_sum_amicable_numbers limit =
- let
- fun iter 1 sum = iter 2 sum
- | iter num sum =
- (* cannot pattern-match with "limit" as name, because it
- would be interpreted as shadowing the outer limit
- binding. *)
- if num < limit
- then
- if is_amicable num then
- (* let only for printing something *)
- let
- val _ = print (String.concat ["amicable number:", Int.toString num, "\n"]);
- in
- iter (num + 1) (sum + num)
- end
- else
- iter (num + 1) sum
- else
- sum
- in
- iter 1 0
- end;
- calculate_sum_amicable_numbers 10000;
|