私はGoチュートリアルを行っていますが、演習:ループと関数でこれよりもニュートンの方法を使用して平方根を計算するよりエレガントな方法があるかどうか疑問に思っています。
func Sqrt(x float64) float64 {
count := 0
var old_z, z float64 = 0, 1
for ; math.Abs(z-old_z) > .001; count++ {
old_z, z = z, z - (z*z - x) / 2*z
}
fmt.Printf("Ran %v iterations\n", count)
return z
}
(仕様の一部は、反復回数を提供することです。)これは、パッケージステートメント、インポート、メインを含む完全なプログラムです。
まず、アルゴリズムが正しくありません。式は次のとおりです。
これを次のようにモデル化しました。
z - (z*z - x) / 2*z
ただし、次のようにする必要があります。
z - (z*z - x)/2/z
または
z - (z*z - x)/(2*z)
(あなたの間違った式には、同じように近くに取得するためにも、五十万回の繰り返しのように実行する必要がありました0.001
!4回の繰り返しのような正しい式が使用する限り近くに取得する1e-6
の場合x = 2
)。
次に、の初期値はz=1
乱数には最適ではありません(のような小さな数値ではうまくいく場合があります2
)。あなたはでキックオフすることができz = x / 2
、非常に簡単な初期値であり、少ない工程で近い結果にあなたをとります。
必ずしも読みやすくなったりエレガントになったりしないその他のオプションは主観的なものです。
結果に名前を付けてz
、returnステートメントを「ベア」にすることができます。また、ループ変数を作成して、現在の「終了」条件をループに移動すると、反復をカウントして、反復カウントを出力して単純に戻ることができるループを作成できます。計算をの初期化部分に移動することもできますif
。
func Sqrt(x float64) (z float64) {
z = x / 2
for i, old := 1, 0.0; ; i++ {
if old, z = z, z-(z*z-x)/2/z; math.Abs(old-z) < 1e-5 {
fmt.Printf("Ran %v iterations\n", i)
return
}
}
}
z = x / 2
をの初期化部分に移動することもできfor
ますが、名前付きの結果をz
作成することはできません(そうでなければ、名前付きの戻り値を隠すローカルバリアントが作成されます)。
func Sqrt(x float64) float64 {
for i, z, old := 1, x/2, 0.0; ; i++ {
if old, z = z, z-(z*z-x)/2/z; math.Abs(old-z) < 1e-5 {
fmt.Printf("Ran %v iterations\n", i)
return z
}
}
}
注:1
私の場合の「終了」条件は内にfor
あり、の条件ではないため、私は反復カウンターを開始しましたfor
。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加