斐波那契法(即贪心算法)
在“埃及分数(一)”中,我们讨论了斐波那契法(即贪心算法)。现在使用 C 语言写一个程序来实现该算法吧,下面就是 EgyptianFibonacci.c:
1: #include
2: #include
3:
4: int main(int argc, char *argv[])
5: {
6: if (argc != 3) return 1;
7: mpz_t z, w;
8: mpq_t x, y;
9: mpz_inits(z, w, 0);
10: mpq_inits(x, y, 0);
11: mpz_set_str(z, argv[1], 10);
12: mpz_set_str(w, argv[2], 10);
13: mpq_set_num(x, z);
14: mpq_set_den(x, w);
15: mpq_canonicalize(x);
16: gmp_printf("%Qd:", x);
17: if (mpq_sgn(x) > 0)
18: {
19: while (1)
20: {
21: mpz_cdiv_q(z, mpq_denref(x), mpq_numref(x));
22: gmp_printf(" %Zd", z);
23: if (mpz_cmp_si(mpq_numref(x), 1) == 0) break;
24: mpq_set_z(y, z);
25: mpq_inv(y, y);
26: mpq_sub(x, x, y);
27: }
28: }
29: mpq_clears(x, y, 0);
30: mpz_clears(z, w, 0);
31: printf("\n");
32: return 0;
33: }
这个程序使用了 GUN MP 高精度算术库,编译时要加上 -lgmp 参数:
$ clang -o EgyptianFibonacci EgyptianFibonacci.c -lgmp
试运行一下:
$ ./EgyptianFibonacci 5 121
5/121: 25 757 763309 873960180913 1527612795642093418846225
$ ./EgyptianFibonacci 118 121
118/121: 2 3 8 60 4840
嗯,运行结果符合我们的预期。
计算单位分数的和
再写个 C 语言程序来验算结果吧,下面就是 UnitFractionSum.c:
1: #include
2:
3: int main(int argc, char *argv[])
4: {
5: mpz_t n;
6: mpz_init(n);
7: mpq_t sum, q;
8: mpq_inits(sum, q, 0);
9: for (int i = 1; i < argc; i++)
10: {
11: mpz_set_str(n, argv[i], 10);
12: mpq_set_si(q, 1, 1);
13: mpq_set_den(q, n);
14: mpq_canonicalize(q);
15: mpq_add(sum, sum, q);
16: }
17: gmp_printf("%Qd\n", sum);
18: mpz_clear(n);
19: mpq_clears(sum, q, 0);
20: return 0;
21: }
编译:
$ clang -o UnitFractionSum UnitFractionSum.c -lgmp
运行:
$ ./UnitFractionSum 25 757 763309 873960180913 1527612795642093418846225
5/121
$ ./UnitFractionSum 2 3 8 60 4840
118/121
一切正常。
GNU MP 高精度算术库简介
本文中的两个 C 语言程序使用了 GNU MP 高精度算术库。这个库用起来非常简单:
mpz_t 表示整数类型。
mpq_t 表示有理数(分数)类型。
mpz_ 开头的函数用于处理整数。
mpq_ 开头的函数用于处理有理数。
这些类型使用前必须用 mp?_init 函数初始化。
使用后必须用 mp?_clear 函数释放。
mp?_set 开头的函数用于设定初值。
mpq_canonicalize 函数用于对有理数进行规范化,即对分数进行约分。
mp?_add 等函数进行算术运算。
详情请参阅参考资料[2]。
参考资料