Algorithm 如何计算和存储sqrt(n)的数字,最多10^6位小数?

Algorithm 如何计算和存储sqrt(n)的数字,最多10^6位小数?,algorithm,math,decimal,sqrt,Algorithm,Math,Decimal,Sqrt,我在做研究工作。我需要计算并存储2到10^6个位置的平方根。我在谷歌上搜索过这个,但我只得到了一个NASA页面,但他们是如何计算的,我不知道。我用C++的SETIO精度。但这只能让结果达到大约50个位置。我该怎么办 美国宇航局网页链接: 我也尝试过二进制搜索,但没有成功 long double ans = sqrt(n); cout<<fixed<<setprecision(50)<<ans<<endl; long-double-ans=sqrt

我在做研究工作。我需要计算并存储2到10^6个位置的平方根。我在谷歌上搜索过这个,但我只得到了一个NASA页面,但他们是如何计算的,我不知道。我用C++的SETIO精度。但这只能让结果达到大约50个位置。我该怎么办

美国宇航局网页链接: 我也尝试过二进制搜索,但没有成功

long double ans = sqrt(n);
cout<<fixed<<setprecision(50)<<ans<<endl;
long-double-ans=sqrt(n);

cout您可以使用大整数,例如Java中的BigInteger。然后计算2e12或2e14的平方根。请注意,sqrt(2)=1.4142。。。和sqrt(200)=14.142。。。然后你可以用巴比伦的方法得到所有的数字:例如S=10^14。x(n+1)=(x(n)+S/x(n))/2。重复此步骤,直到x(n)不变。也许有更高效的算法收敛得更快。

这里有各种选择。您可以使用任意精度浮点库(例如用C或C++,或Python中的内置库)。若您知道库中给出的错误保证,则可以确保获得正确的十进制数字。例如,MPFR和Python的
decimal
在这里都能保证正确的舍入,但MPFR的缺点是(对于获取十进制数字的特定用例)它是二进制的,因此您还需要分析由二进制到十进制转换引起的错误

您还可以使用纯整数方法,使用任意精度整数库(如),或支持任意精度的现成整数的语言(例如,Java及其BigInteger类:Java的最新版本提供了一种方法):scale
2
by
10**2n
,其中,
n
是小数点后所需的位数,取整数平方根(即精确数学平方根的整数部分),然后按
10**n
缩小。有关计算整数平方根的相对简单但有效的算法,请参见下文

如果您愿意使用另一种语言,这里最简单的开箱即用选项是使用Python的
decimal
库。这里是您所需要的所有代码,假设是Python 3(而不是Python 2,在Python 2中速度会非常慢)

str(Decimal(2).sqrt())
操作在我的机器上花费的时间不到10秒。让我们检查长度,以及前一百位和后一百位数字(我们显然不能在这里复制整个输出):

这有一个小问题:结果保证是正确的四舍五入,但这是四舍五入的,而不是截断的。这意味着最后的“4”位可能是最后一次四舍五入的结果,也就是说,该位置的实际数字可能是“3”,后面是“8”或“9”(例如)

我们可以通过计算两个额外的数字来解决这个问题,然后对它们进行截断(在仔细检查这些额外数字的舍入是否影响截断后)

因此,小数点后的第一百万位数实际上是3,而不是4。请注意,如果上面计算的最后3个数字是“400”,我们仍然不知道第一百万个数字是“3”还是“4”,因为“400”可能再次是一个四舍五入的结果。在这种情况下,您可以计算另外两个数字并重试,以此类推,当您有明确的输出时停止。(欲进一步阅读,请搜索“制表者的困境”。)

(请注意,将
decimal
模块的舍入模式设置为
ROUND_DOWN
在此处不起作用,因为
decimal.sqrt
方法忽略舍入模式。)

如果您想使用纯整数算术来实现这一点,Python3.8提供了一个
math.isqrt
函数来计算精确的整数平方根。在这种情况下,我们将按如下方式使用它:

>>> from math import isqrt
>>> sqrt2_digits = str(isqrt(2*10**(2*10**6)))
这需要更长的时间:在我的笔记本电脑上大约20秒。其中一半时间用于
str
调用中隐含的二进制到十进制转换。但这一次,我们直接得到了截断的结果,不必担心四舍五入会给我们带来错误的最终数字

再次检查结果:

>>> len(sqrt2_digits)
1000001
>>> sqrt2_digits[:100]
'1414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641572'
>>> sqrt2_digits[-100:]
'2637136344700072631923515210207475200984587509349804012374947972946621229489938420441930169048412043'
这有点骗人,因为(在撰写本文时)Python 3.8尚未发布,尽管是beta版。但是在中有一个纯Python版本的
isqrt
算法,您可以直接复制、粘贴和使用。全文如下:

import operator

def isqrt(n):
    """
    Return the integer part of the square root of the input.
    """
    n = operator.index(n)

    if n < 0:
        raise ValueError("isqrt() argument must be nonnegative")
    if n == 0:
        return 0

    c = (n.bit_length() - 1) // 2
    a = 1
    d = 0
    for s in reversed(range(c.bit_length())):
        # Loop invariant: (a-1)**2 < (n >> 2*(c - d)) < (a+1)**2
        e = d
        d = c >> s
        a = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a

    return a - (a*a > n)
导入操作符
def isqrt(n):
"""
返回输入平方根的整数部分。
"""
n=运算符索引(n)
如果n<0:
raise VALUERROR(“isqrt()参数必须为非负”)
如果n==0:
返回0
c=(n.位长度()-1)//2
a=1
d=0
对于反转的s(范围(c.位长度()):
#循环不变量:(a-1)**2<(n>>2*(c-d))<(a+1)**2
e=d
d=c>>s
a=(a>2*c-e-d+1)//a
返回一个-(a*a>n)
源代码还包含对上述算法的解释以及对其正确性的非正式证明


您可以检查上述两种方法的结果是否一致(以第一个结果中额外的小数点为模)。它们是由完全不同的方法计算的,因此这两种方法都可以作为健全性检查。

欢迎使用堆栈溢出。您是只想要一个算法(如在标记中)还是想要代码?你想使用C++还是其他语言也合适?答案是使用库还是需要基本代码?牛顿的迭代有什么问题吗?相关@conditionalMethod:啊,没有。我在Python标准库中使用了
math.isqrt
,这是Python 3.8中的新版本(严格地说,它还没有发布)。顺便说一句,“运行时间是整数位长度中的线性时间”的说法对于PyPI isqrt包显然是错误的。@MarkDickinson我忘了说谢谢。事实上,我是为你找的
>>> from math import isqrt
>>> sqrt2_digits = str(isqrt(2*10**(2*10**6)))
>>> len(sqrt2_digits)
1000001
>>> sqrt2_digits[:100]
'1414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641572'
>>> sqrt2_digits[-100:]
'2637136344700072631923515210207475200984587509349804012374947972946621229489938420441930169048412043'
import operator

def isqrt(n):
    """
    Return the integer part of the square root of the input.
    """
    n = operator.index(n)

    if n < 0:
        raise ValueError("isqrt() argument must be nonnegative")
    if n == 0:
        return 0

    c = (n.bit_length() - 1) // 2
    a = 1
    d = 0
    for s in reversed(range(c.bit_length())):
        # Loop invariant: (a-1)**2 < (n >> 2*(c - d)) < (a+1)**2
        e = d
        d = c >> s
        a = (a << d - e - 1) + (n >> 2*c - e - d + 1) // a

    return a - (a*a > n)