原始的な表現とは、+ - * / sqrt
私が見逃しているものが他にない限り、という意味です。これらの関数だけを使って 6 乗根を求める Scheme 式を書くにはどうすればよいか考えています。
平方根の立方根を見つけることができることは知っていますが、立方根は原始式ではないようです。
原始的な表現とは、+ - * / sqrt
私が見逃しているものが他にない限り、という意味です。これらの関数だけを使って 6 乗根を求める Scheme 式を書くにはどうすればよいか考えています。
平方根の立方根を見つけることができることは知っていますが、立方根は原始式ではないようです。
2 番目の引数として分数べき乗を渡すexptを考えてみましょう。
しかし、 について知らなかったとしましょうexpt
。まだ計算できますか?
それを行う 1 つの方法は、ニュートン法などを適用することです。たとえば、n^(1/4) を計算したいとしましょう。もちろん、これsqrt
を行うのに 2 回だけ使用できることは既にわかっていますが、ニュートンの方法がこの問題にどのように適用されるかを見てみましょう。
が与えられた場合、関数のn
根を発見したいと思いx
ます:
f(x) = x^4 - n
具体的には、 を探したい場合は16^(1/4)
、関数のルートを探します。
f(x) = x^4 - 16
そこにプラグインすれば、それがこの関数のルートであるx=2
ことがわかります。2
しかし、私たちはそれを知らなかったと言います。x
この関数をゼロにする値をどのように見つけますか?
ニュートンの方法によると、 を推測した場合x
、それを と呼びx_0
、次のプロセスを実行することでその推測を改善できます。
x_1 = x_0 - f(x_0) / f'(x_0)
ここでは の導関数f'(x)
の表記です。上記の場合、 の導関数はです。f(x)
f(x)
4x^3
x_2
そして、計算を繰り返すことで、 、x_3
、 ... をより正確に推測できます。
x_2 = x_1 - f(x_1) / f'(x_1)
x_3 = x_2 - f(x_2) / f'(x_2)
...
私たちが飽きるまで。
これをすべてコードで書きましょう。
(define (f x)
(- (* x x x x) 16))
(define (f-prime x)
(* 4 x x x))
(define (improve guess)
(- guess (/ (f guess)
(f-prime guess))))
(define approx-quad-root-of-16
(improve (improve (improve (improve (improve 1.0))))))
上記のコードは、 、 、および最初の推測を 5 回改善するという考えを表しているだけf(x)
ですf'(x)
。の値が何であるかを見てみましょうapprox-quad-root-of-16
。
> approx-quad-root-of-16
2.0457437305170534
ねえ、かっこいい。それは実際に何かをしており、に近い2
です。のような悪い最初の推測から始めるのは悪くありません1.0
。
もちろん、16
そこにハードコードするのは少しばかげています。一般化して、代わりに任意のものを取る関数に変えて、n
何でも四重根を計算できるようにしましょう。
(define (approx-quad-root-of-n n)
(define (f x)
(- (* x x x x) n))
(define (f-prime x)
(* 4 x x x))
(define (improve guess)
(- guess (/ (f guess)
(f-prime guess))))
(improve (improve (improve (improve (improve 1.0))))))
これは何か効果がありますか?どれどれ:
> (approx-quad-root-of-n 10)
1.7800226459895
> (expt (approx-quad-root-of-n 10) 4)
10.039269440807693
クール: 何か役に立つことをしています。ただし、まだそれほど正確ではないことに注意してください。より良い精度を得るにはimprove
、4 回または 5 回だけでなく、 を呼び出し続ける必要があります。ループまたは再帰を考えてください。解決策が「十分に近い」まで改善を繰り返します。
これは、この種の問題を解決する方法のスケッチです。もう少し詳しく知りたい場合は、 Structure and Interpretation of Computer Programs の平方根の計算に関するセクションを参照してください。
数値的な方法を試してみるのもいいかもしれませんが、これは数値が大きい場合には非効率的かもしれませんが、うまくいきます。
またpow
、プリミティブとしてもカウントする場合 ( もカウントするためsqrt
)、これを行うことができます。
pow(yournum, 1/6);