根本問題是,您無法準確地將非方形的平方根表示爲浮點數。
如果ξ
被精確值和x
近似(其被認爲是仍然相當好,從而尤其floor(ξ) = a = floor(x)
仍然成立),則連分數算法的下一步驟之後的差是
ξ' - x' = 1/(ξ - a) - 1/(x - a) = (x - ξ)/((ξ - a)*(x - a)) ≈ (x - ξ)/(ξ - a)^2
因此我們看到,在每一步中,近似值和實際值之間的差值的絕對值增加,因爲0 < ξ - a < 1
。每當發生大的部分商(ξ - a
接近於0)時,差異增加很大的因數。一旦(差異的絕對值)等於或大於1,下一個計算得到的部分商被保證是錯誤的,但很可能第一個錯誤的部分商出現得更早。
Charlesmentioned近似與原始逼近n
正確的數字,你可以計算連續分數約n
部分商。這是一個很好的經驗法則,但正如我們所看到的,任何大的部分商都會花費更多的精度,從而減少可獲得的部分商的數量,並且偶爾會在更早的時候得到錯誤的部分商。
√139
的情況是一個相對較長的週期和一些大的部分商,所以在這個週期完成之前出現第一個錯誤計算的部分商並不奇怪(我很驚訝它沒有' t更早發生)。
使用浮點運算,沒有辦法阻止這種情況。
但是對於二次感應的情況,我們可以通過僅使用整數算術來避免這個問題。假設你要計算的
ξ = (√D + P)/Q
其中Q
分D - P²
和D > 1
是不是一個完美的正方形(如果整除條件不滿足,你可以用P*Q
和Q
代之以D
與D*Q²
,P
連分數擴展Q²
;你的情況是P = 0, Q = 1
,在那裏它平凡滿意)。將完整商品寫爲
ξ_k = (√D + P_k)/Q_k (with ξ_0 = ξ, P_0 = P, Q_0 = Q)
並且表示部分商a_k
。然後
ξ_k - a_k = (√D - (a_k*Q_k - P_k))/Q_k
,並與P_{k+1} = a_k*Q_k - P_k
,
ξ_{k+1} = 1/(ξ_k - a_k) = Q_k/(√D - P_{k+1}) = (√D + P_{k+1})/[(D - P_{k+1}^2)/Q_k],
所以Q_{k+1} = (D - P_{k+1}^2)/Q_k
—因爲P_{k+1}^2 - P_k^2
是Q_k
的倍數,通過感應Q_{k+1}
是整數,並且Q_{k+1}
劃分D - P_{k+1}^2
。
的實數ξ
的持續分數展開是週期性的,當且僅當ξ
是二次清音,並且期間結束時在上述算法中,第一對(P_k, Q_k)
重複。純平方根的情況特別簡單,當k > 0
的第一個Q_k = 1
和P_k, Q_k
總是非負時,該時段完成。
隨着R = floor(√D)
,部分商可以如
a_k = floor((R + P_k)/Q_k)
被計算,以便對上述算法的代碼變得
std::vector<unsigned long> sqrtCF(unsigned long D) {
// sqrt(D) may be slightly off for large D.
// If large D are expected, a correction for R is needed.
unsigned long R = floor(sqrt(D));
std::vector<unsigned long> f;
f.push_back(R);
if (R*R == D) {
// Oops, a square
return f;
}
unsigned long a = R, P = 0, Q = 1;
do {
P = a*Q - P;
Q = (D - P*P)/Q;
a = (R + P)/Q;
f.push_back(a);
}while(Q != 1);
return f;
}
這就容易計算的(例如)√7981
持續餾分具有周期長度爲182.
A和B的類型是什麼? –
@PaulR A是雙B是int –
我的答案在這裏可能會有所幫助。它生成並打印出任意「double」的連續分數。 – Mysticial