プロシジャーを一般的なメソッドにする、fixed-point を探す。
問題
練習1.34:(define (f g) (g 2)) がある、(f f) は何でしょう?
練習1.35:Fixed-point を利用して、黄金率を求める。
練習1.36:改善されたFixed-point。平均緩和法。
練習1.37:連分数。
練習1.38:e を求める。
練習1.39:tan(x) を求める。
解答
練習1.34の解答
f(g) = g(2)だから、f(f) = f(2) = 2(2)、エラーとなります。
練習1.35の解答
-
-
-
-
- const float TOLERANCE = 0.00001;
-
- static float goldenRatio(float x) {
- return 1 + 1/x;
- }
-
- float fixedPoint(float function(float) f, float firstGuess) {
- bool closeEnough(float v1, float v2) {
- return abs(v1 - v2) < TOLERANCE;
- }
-
- float tryIt(float guess) {
- float next = f(guess);
- if (closeEnough(guess, next)) {
- return next;
- }
- return tryIt(next);
- }
-
- return tryIt(firstGuess);
- }
-
- void main() {
- float ret;
-
-
- Stdout("---- 1.35 ----").newline;
- ret = fixedPoint(&goldenRatio, 1.0);
- Stdout.formatln("goldenRatio = {:f16}", ret);
- }
/** * 練習1.35。 * Fixed-point を利用して、黄金率を求める。 */ const float TOLERANCE = 0.00001; static float goldenRatio(float x) { return 1 + 1/x; } float fixedPoint(float function(float x) f, float firstGuess) { bool closeEnough(float v1, float v2) { return abs(v1 - v2) < TOLERANCE; } float tryIt(float guess) { float next = f(guess); if (closeEnough(guess, next)) { return next; } return tryIt(next); } return tryIt(firstGuess); } void main() { float ret; // for 1.35 Stdout("---- 1.35 ----").newline; ret = fixedPoint(&goldenRatio, 1.0); Stdout.formatln("goldenRatio = {:f16}", ret); }
実行結果。
---- 1.35 ----
goldenRatio = 1.6180328130722046 |
練習1.36の解答
-
-
-
-
- int loop = 0;
-
- float fixedPoint2(float function(float) f, float firstGuess) {
- bool closeEnough(float v1, float v2) {
- return abs(v1 - v2) < TOLERANCE;
- }
-
- float tryIt(float guess) {
- loop++;
- float next = f(guess);
- Stdout.format("{:f5}\t", next);
- if (closeEnough(guess, next)) {
- return next;
- }
- return tryIt(next);
- }
-
- return tryIt(firstGuess);
- }
-
-
- static float fpNoDamping(float x) {
- return log(1000) / log(x);
- }
-
-
- static float fpDamping(float x) {
- float total = x + (log(1000) / log(x));
- return total / 2;
- }
/** * 練習1.36。 * 改善されたFixed-point。平均緩和法。 */ int loop = 0; float fixedPoint2(float function(float x) f, float firstGuess) { bool closeEnough(float v1, float v2) { return abs(v1 - v2) < TOLERANCE; } float tryIt(float guess) { loop++; float next = f(guess); Stdout.format("{:f5}\t", next); if (closeEnough(guess, next)) { return next; } return tryIt(next); } return tryIt(firstGuess); } // 平均緩和法を使わない static float fpNoDamping(float x) { return log(1000) / log(x); } // 平均緩和法を使う static float fpDamping(float x) { float total = x + (log(1000) / log(x)); return total / 2; }
実行結果。
---- 1.36 ----
4.29203 4.74186 4.43820 4.63530 4.50398 4.58999 4.53301 4.57048 4.54572 4.562024.55126 4.55836 4.55368 4.55676 4.55473 4.55607 4.55518 4.55577 4.55538 4.555644.55547 4.55558 4.55551 4.55555 4.55552 4.55554 4.55553 4.55554
[No average damping] Root = 4.55554, loop = 28
4.64601 4.57161 4.55829 4.55601 4.55562 4.55555 4.55554 4.55554
[With average damping] Root = 4.55554, loop = 8 |
平均緩和法を利用することで、計算が遥に早くなりました。
練習1.37の解答
-
-
-
-
- static float n(int i) {
- return 1.0f;
- }
-
- static float d(int i) {
- return 1.0f;
- }
-
-
- float contFrac(float function(int) n, float function(int) d, int k) {
- float iter(int m) {
- if (m == k) {
- return n(k) / d(k);
- }
- return n(m) / (d(m) + iter(m + 1));
- }
- return iter(1);
- }
-
-
- float contFrac2(float function(int) n, float function(int) d, int k) {
- float iter(int m, float result) {
- if (m == 1) {
-
- return result;
- }
- return iter(m - 1, n(m-1) / (d(m-1) + result));
- }
- return iter(k, n(k)/d(k));
- }
/** * 練習1.37。 * 連分数。 */ static float n(int i) { return 1.0f; } static float d(int i) { return 1.0f; } // 再帰版 float contFrac(float function(int i) n, float function(int j) d, int k) { float iter(int m) { if (m == k) { return n(k) / d(k); } return n(m) / (d(m) + iter(m + 1)); } return iter(1); } // 反復版 float contFrac2(float function(int i) n, float function(int j) d, int k) { float iter(int m, float result) { if (m == 1) { // 0 まではだめ return result; } return iter(m - 1, n(m-1) / (d(m-1) + result)); } return iter(k, n(k)/d(k)); }
実行結果。
---- 1.37 ----
[再帰] contFrac(&n, &d, 11) = 0.6180555820465088
[反復] contFrac2(&n, &d, 11) = 0.6180555820465088 |
k >= 11 時、4位の精度が保証できます。
練習1.38の解答
-
-
-
-
- static float d2(int i) {
- int div = i / 3;
- int mod = i % 3;
- float ret;
- if (mod == 0 || mod == 1) {
- ret = 1;
- } else {
- ret = 2 * (div + 1);
- }
- return ret;
- }
-
- float e(int k) {
- return contFrac2(&n, &d2, k) + 2;
- }
/** * 練習1.38。 * e を求める。 */ static float d2(int i) { int div = i / 3; int mod = i % 3; float ret; if (mod == 0 || mod == 1) { ret = 1; } else { ret = 2 * (div + 1); } return ret; } float e(int k) { return contFrac2(&n, &d2, k) + 2; }
実行結果。
---- 1.38 ----
e(10) = 2.7182817459106445 |
練習1.39の解答
-
-
-
-
- static float n3(float x, int i) {
- if (i == 1) {
- return x;
- } else {
- return - x*x;
- }
- }
-
- static float d3(int i) {
- return 2 * i - 1;
- }
-
- float contFrac3(float function(float, int) n, float function(int) d, int k, float x) {
- float iter(int m, float result) {
- if (m == 1) {
-
- return result;
- }
- return iter(m - 1, n(x, m-1) / (d(m-1) + result));
- }
- return iter(k, n(x, k)/d(k));
- }
-
- float tanCf(float x, int k) {
- return contFrac3(&n3, &d3, k, x);
- }
/** * 練習1.39。 * tan(x) を求める。 */ static float n3(float x, int i) { if (i == 1) { return x; } else { return - x*x; } } static float d3(int i) { return 2 * i - 1; } float contFrac3(float function(float, int) n, float function(int) d, int k, float x) { float iter(int m, float result) { if (m == 1) { // 0 まではだめ return result; } return iter(m - 1, n(x, m-1) / (d(m-1) + result)); } return iter(k, n(x, k)/d(k)); } float tanCf(float x, int k) { return contFrac3(&n3, &d3, k, x); }
実行結果。
tanCf(pi/4, 10) = 0.9999999403953552
tanCf(0, 10) = 0.0000000000000000
tanCf(1, 10) = 1.5574077367782593 |
|