您的代码没有计算n
. 它尝试计算已计算的连分数√n
。我的意思是没关系,但是,如果它是正确的,你的方法更适合一般十进制到理性的转换。然而,对于常规(简单)连分数(所有分子都是 1)的 sqrt 函数,算法略有不同。
然而问题还没有结束。是的,作为一项规则,CF 系数√n
是重复回文的形式,它以第一个非零系数的双倍结尾。比如√31 =[5;1,1,3,5,3,1,1,10,1,1,3,5,3,1,1,10..]
。现在没有简单的方法来查询每个给定的回文长度n
。有一些已知的模式,但它们远未定义所有的通用模式n
。所以在第一个回文结束时停止迭代是一种非常不确定的方法。想象
__
√226 =[15;30]
尽管
____________________________________________________
√244 =[15;1,1,1,1,1,2,1,5,1,1,9,1,6,1,9,1,1,5,1,2,1,1,1,1,1,30]
如果您决定在2*f[0]
大多数情况下停止迭代,您会得到一个像 in 这样的错误近似值,或者像 in case√226
这样一个过度计算的近似值。√244
此外,一旦n
成长,追逐回文的尽头变得更加没有意义,因为你永远不需要这样的精确度。
___________________________________________________________________________________________________________________________________________________________________________
√7114 = [84;2,1,9,3,1,10,2,23,1,1,1,1,1,2,1,27,2,1,1,3,1,2,1,1,1,16,4,3,1,3,2,1,6,18,1,1,2,6,11,11,6,2,1,1,18,6,1,2,3,1,3,4,16,1,1,1,2,1,3,1,1,2,27,1,2,1,1,1,1,1,23,2,10,1,3,9,1,2,168]
在这种情况下,一旦获得必要的精度就停止迭代是合理的。正如我在开头提到的,有两种方法。
- 一般的 Decimal to Rational 算法从任何十进制数中获得简单的连分数。这将使 CF 精确解析为该小数,而不会出现任何浮点错误。有关此算法的详细说明,您可以查看我以前的答案。
- 碰巧有一个更直接的算法,
√n
它与 1 基本相同,但针对平方根进行了调整。在这种情况下,您不提供√n
but n
。
思路如下。我们必须为在分子处包含平方根值的输入定义一个通用形式。然后我们尝试在连分数部分达到相同的表达式以便能够迭代。
让我们的输入是形式
q + √n
______
p
对于简单的平方根运算,我们可以假设q
is0
和p
is 1
。如果我们可以在下一阶段建立这种形式,那么我们可以轻松地进行迭代。
从初始阶段开始,其中,q = 0
是的整数部分和是浮点部分,我们的目标是带入形式;p = 1
m
√n
1/x
x
(q + √n) / p
1 1 1 (√n + m) √n + m
√n = m + ___ ⇒ x = _______ ⇒ x = ________ . ________ ⇒ x = ________
x √n - m (√n - m) (√n + m) n - m^2
现在√n
在分子处,我们有以下形式;
√n + q
x = ______
p
哪里q = m
和p = n - m^2
。就在这一点上,您可以计算x
,然后m'
按地板计算x
。它成为了;
√n + q 1 p p(√n - (q - pm')) p(√n + (pm' - q))
x = ______ = m' + ___ ⇒ x' = ______________ = _________________ = _________________
p x' √n + (q - pm') n - (q - pm')^2 n - (q - pm')^2
此时n - (q - pm')^2
分母的 at 可以被分子的 at 整除p
。现在这是稳定的,我们可以根据需要扩展它。让我们为q
and分配新的任务p
;
q' = pm'-q;
p' = (n - q'^2)/p;
√n + q'
x' = ______
p'
请注意,当p'
变为 1 ( n - q'^2 = p
) 时,我们处于回文的末尾。然而,为了决定在哪里停止,我使用了与我的 toRational 算法中描述的机制相同的机制,正如上面备选方案 1 中链接的那样。一旦达到 JS 浮点分辨率,它基本上就会停止。JavaScript 代码如下;
function rationalSqrt(n){
var nr = Math.sqrt(n),
m = Math.floor(nr),
p = n-m**2,
q = m,
cs = [m],
n0 = 1,
d0 = 0,
n1 = m,
d1 = 1,
n2 = 0,
d2 = 1;
if (nr === m) return {n:m,d:1,cs};
while (Math.abs(nr-n2/d2) > Number.EPSILON){
m = Math.floor((nr+q)/p);
q = m*p-q;
p = (n-q**2)/p;
cs.push(m);
n2 = m*n1+n0;
d2 = m*d1+d0;
n0 = n1;
d0 = d1;
n1 = n2;
d1 = d2;
}
return {n:n2,d:d2,cs};
}
这两种算法略有不同。
- 约 60% 的时间它们产生相同的分数。
- 大约 27% 的时间
toRational
在 JS 浮点分辨率内给出更小的分子和分母。
- 大约 13% 的时间
rationalSqrt
(这一次)在 JS 浮点分辨率内给出更小的分子和分母。
rationalSqrt
将产生精确的系数,正如人们期望的平方根一样,但一旦分辨率足够,就会被截断。
toRational
给出了预期的 couse 系数,但最后一个可能与您对平方根系列的期望完全无关。
一个这样的例子是;
rationalSqrt(511); //returns
{ n : 882184734
, d : 39025555
, cs: [22,1,1,1,1,6,1,14,4,1,21,1,4,14,1,6,1]
}
尽管
toRational(Math.sqrt(511));
{ n : 1215746799
, d : 53781472
, cs: [22,1,1,1,1,6,1,14,4,1,21,1,4,14,1,10]
}
进一步的想法:考虑给我们RCF系数。我们可以反转rationalSqrt
算法来获得它的(q + √n) / p
形式吗?这可能是一项有趣的任务。