5問目
2520 は 1 から 10 までのそれぞれの数で割り切れる最小の数です.
http://projecteuler.net/index.php?section=problems&id=5
では, 1 から 20 までの全ての数で割り切れる最小の数は何?
数学的にも簡単だし, アルゴリズム的にもすっきり書けるのであまり悩まなかったが, 出てきた答えが案外大きな数字で驚いた.
因みに Lisp で書くと,
(lcm 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
シンプルで素晴しい.
Project Euler の2周目では, Lisp にしようかしら?それか, C での最小長プログラムに挑戦しようかしら?
3問目で使った prime 関数をここでも使っている.
今は
$ gcc Problem005.c ../../lib/prime.o -o Problem005
なんてやってるが, そのうちライブラリ化しておきたい.
/* Problem005.c */ #include <stdio.h> #include <math.h> #include <unistd.h> #include <ctype.h> #include "prime.h" #define DEFAULT_NUMBER 20 long solveVer00(int); long solveVer01(int); int version; int number; int parseArg(int, char**); long lcm(long, long); long gcd(long, long); int main(int argc, char **argv) { if (parseArg(argc, argv) == EXIT_FAILURE) { return EXIT_FAILURE; } switch (version) { case 0: fprintf(stdout, "Solution: %ld.\n", solveVer00(number)); break; case 1: fprintf(stdout, "Solution: %ld.\n", solveVer01(number)); break; default: break; } return EXIT_SUCCESS; } long solveVer00(int number) { int i; long result; result = 1; for (i = 1; i < number; i++) { result = lcm(result, i); } return result; } long solveVer01(int number) { int p; int power; long result; result = 1; prime(20); while ((p = prime(0)) != -1) { power = (int) (log(number) / log(p)); result *= pow(p, power); } return result; } long gcd(long num1, long num2) { long temp; while (num2 > 0) { temp = num1 % num2; num1 = num2; num2 = temp; } return num1; } long lcm(long num1, long num2) { return num1 * num2 / gcd(num1, num2); } int parseArg(int argc, char **argv) { int optChar; // default values version = 0; while ((optChar = getopt(argc, argv, "v:")) != -1) { switch (optChar) { case 'v': version = atoi(optarg); break; case '?': if (optopt == 'c') { fprintf(stderr, "Option -%c requires an argument.\n", optopt); } else if (isprint(optopt)) { fprintf(stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); } return EXIT_FAILURE; default: abort(); } } if (optind == argc) { number = DEFAULT_NUMBER; } else { number = atoi(argv[optind]); } return EXIT_SUCCESS; }
/* prime.h */ #ifndef __PRIME_H__ #define __PRIME_H__ #include <stdlib.h> #include <stdio.h> long long prime(long long); #endif
/* prime.c */ #include "prime.h" long long prime(long long value) { static long long maxValue; static long long currentPrime; static int *primes; long long i; if (value > 0) { // reset maxValue = value; currentPrime = 1; if (primes != NULL) { free(primes); } if ((primes = malloc(sizeof(int) * maxValue)) == NULL) { fprintf(stderr, "Error: failed to malloc.\n"); exit(EXIT_FAILURE); } /* * 0: not prime * 1: prime */ primes[0] = 0; primes[1] = 0; for (i = 2; i < maxValue; i++) { primes[i] = 1; } return 0; } else { // return next prime // search next prime number currentPrime++; while (currentPrime < maxValue && primes[currentPrime] == 0) { currentPrime++; } if (currentPrime == maxValue) { return -1; } // get prime flags down for (i = currentPrime * 2; i < maxValue; i += currentPrime) { primes[i] = 0; } return currentPrime; } }