生成 2 的平方根的数字

发布于 2024-10-20 05:31:10 字数 262 浏览 1 评论 0原文

我想生成二到三百万位数字的平方根的数字。

我知道Newton-Raphson 但由于缺乏 biginteger 支持,我不太清楚如何在 C 或 C++ 中实现它。有人能指出我正确的方向吗?

另外,如果有人知道如何用 python 做到这一点(我是初学者),我也将不胜感激。

I want to generate the digits of the square root of two to 3 million digits.

I am aware of Newton-Raphson but I don't have much clue how to implement it in C or C++ due to lack of biginteger support. Can somebody point me in the right direction?

Also, if anybody knows how to do it in python (I'm a beginner), I would also appreciate it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

夏末 2024-10-27 05:31:10

您可以尝试使用映射:

a/b -> (a+2b)/(a+b)a= 1, b= 1 开始。这收敛于 sqrt(2)(实际上给出了它的连分数表示)。

现在是关键点:这可以表示为矩阵乘法(类似于斐波那契)

如果 a_n 和 b_n 是步骤中的第 n 个数字,则

[1 2] [a_n b_n]T = [a_( n+1) b_(n+1)]T
[1 1]

现在给出

[1 2]n [a_1 b_1]T = [a_(n+1) b_(n+1)] T
[1 1]

因此,如果 2x2 矩阵是 A,我们需要计算 An,这可以通过重复平方来完成,并且仅使用整数运算(因此您不必担心精度问题) 。

另请注意,您得到的 a/b 将始终采用简化形式(如 gcd(a,b) = gcd(a+2b, a+b)),因此如果您正在考虑使用分数类来表示中间值结果,不要!

由于第 n 个分母类似于 (1+sqrt(2))^n,因此要获得 300 万位数字,您可能需要计算到第 3671656 项。

请注意,即使您正在寻找约 360 万项,重复平方也将允许您在 O(Log n) 乘法和加法中计算第 n 项。

此外,与 Newton-Raphson 等迭代不同,这可以很容易地并行化。

You could try using the mapping:

a/b -> (a+2b)/(a+b) starting with a= 1, b= 1. This converges to sqrt(2) (in fact gives the continued fraction representations of it).

Now the key point: This can be represented as a matrix multiplication (similar to fibonacci)

If a_n and b_n are the nth numbers in the steps then

[1 2] [a_n b_n]T = [a_(n+1) b_(n+1)]T
[1 1]

which now gives us

[1 2]n [a_1 b_1]T = [a_(n+1) b_(n+1)]T
[1 1]

Thus if the 2x2 matrix is A, we need to compute An which can be done by repeated squaring and only uses integer arithmetic (so you don't have to worry about precision issues).

Also note that the a/b you get will always be in reduced form (as gcd(a,b) = gcd(a+2b, a+b)), so if you are thinking of using a fraction class to represent the intermediate results, don't!

Since the nth denominators is like (1+sqrt(2))^n, to get 3 million digits you would likely need to compute till the 3671656th term.

Note, even though you are looking for the ~3.6 millionth term, repeated squaring will allow you to compute the nth term in O(Log n) multiplications and additions.

Also, this can easily be made parallel, unlike the iterative ones like Newton-Raphson etc.

旧情勿念 2024-10-27 05:31:10

编辑:我比以前更喜欢这个版本。这是一个通用的解决方案,接受整数和小数;当 n = 2 且精度 = 100000 时,大约需要两分钟。感谢 Paul McGuire 的建议和建议。欢迎其他建议!

def sqrt_list(n, precision):
    ndigits = []        # break n into list of digits
    n_int = int(n)
    n_fraction = n - n_int

    while n_int:                            # generate list of digits of integral part
        ndigits.append(n_int % 10)
        n_int /= 10
    if len(ndigits) % 2: ndigits.append(0)  # ndigits will be processed in groups of 2

    decimal_point_index = len(ndigits) / 2  # remember decimal point position
    while n_fraction:                       # insert digits from fractional part
        n_fraction *= 10
        ndigits.insert(0, int(n_fraction))
        n_fraction -= int(n_fraction)
    if len(ndigits) % 2: ndigits.insert(0, 0)  # ndigits will be processed in groups of 2

    rootlist = []
    root = carry = 0                        # the algorithm
    while root == 0 or (len(rootlist) < precision and (ndigits or carry != 0)):
        carry = carry * 100
        if ndigits: carry += ndigits.pop() * 10 + ndigits.pop()
        x = 9
        while (20 * root + x) * x > carry:
                x -= 1
        carry -= (20 * root + x) * x
        root = root * 10 + x
        rootlist.append(x)
    return rootlist, decimal_point_index

EDIT: I like this version better than the previous. It's a general solution that accepts both integers and decimal fractions; with n = 2 and precision = 100000, it takes about two minutes. Thanks to Paul McGuire for his suggestions & other suggestions welcome!

def sqrt_list(n, precision):
    ndigits = []        # break n into list of digits
    n_int = int(n)
    n_fraction = n - n_int

    while n_int:                            # generate list of digits of integral part
        ndigits.append(n_int % 10)
        n_int /= 10
    if len(ndigits) % 2: ndigits.append(0)  # ndigits will be processed in groups of 2

    decimal_point_index = len(ndigits) / 2  # remember decimal point position
    while n_fraction:                       # insert digits from fractional part
        n_fraction *= 10
        ndigits.insert(0, int(n_fraction))
        n_fraction -= int(n_fraction)
    if len(ndigits) % 2: ndigits.insert(0, 0)  # ndigits will be processed in groups of 2

    rootlist = []
    root = carry = 0                        # the algorithm
    while root == 0 or (len(rootlist) < precision and (ndigits or carry != 0)):
        carry = carry * 100
        if ndigits: carry += ndigits.pop() * 10 + ndigits.pop()
        x = 9
        while (20 * root + x) * x > carry:
                x -= 1
        carry -= (20 * root + x) * x
        root = root * 10 + x
        rootlist.append(x)
    return rootlist, decimal_point_index
千年*琉璃梦 2024-10-27 05:31:10

至于任意大数,您可以查看GNU 多精度算术库(适用于 C/C++)。

As for arbitrary big numbers you could have a look at The GNU Multiple Precision Arithmetic Library (for C/C++).

迷鸟归林 2024-10-27 05:31:10

为了工作?使用图书馆!

为了好玩?对你有好处:)

编写一个程序来模仿你用铅笔和纸所做的事情。从 1 位数字开始,然后是 2 位数字,然后是 3,...,...

不要担心牛顿或其他任何人。按照你的方式去做吧。

For work? Use a library!

For fun? Good for you :)

Write a program to imitate what you would do with pencil and paper. Start with 1 digit, then 2 digits, then 3, ..., ...

Don't worry about Newton or anybody else. Just do it your way.

情泪▽动烟 2024-10-27 05:31:10

这是一个简短的版本,用于计算整数 a数字精度的平方根。它的工作原理是乘以 10 后求出 a 的整数平方根,直到 2 x 位数

def sqroot(a, digits):
    a = a * (10**(2*digits))
    x_prev = 0
    x_next = 1 * (10**digits)
    while x_prev != x_next:
        x_prev = x_next
        x_next = (x_prev + (a // x_prev)) >> 1
    return x_next

只是一些注意事项。

您需要将结果转换为字符串,并在正确的位置添加小数点(如果您想打印小数点)。

将非常大的整数转换为字符串并不是很快。

除很大的整数也不是很快(在 Python 中)。

根据系统的性能,计算 2 到 3 百万位小数的平方根可能需要一个小时或更长时间。

我还没有证明循环总是会终止。它可能在最后一位数字不同的两个值之间振荡。或者也可能不会。

Here is a short version for calculating the square root of an integer a to digits of precision. It works by finding the integer square root of a after multiplying by 10 raised to the 2 x digits.

def sqroot(a, digits):
    a = a * (10**(2*digits))
    x_prev = 0
    x_next = 1 * (10**digits)
    while x_prev != x_next:
        x_prev = x_next
        x_next = (x_prev + (a // x_prev)) >> 1
    return x_next

Just a few caveats.

You'll need to convert the result to a string and add the decimal point at the correct location (if you want the decimal point printed).

Converting a very large integer to a string isn't very fast.

Dividing very large integers isn't very fast (in Python) either.

Depending on the performance of your system, it may take an hour or longer to calculate the square root of 2 to 3 million decimal places.

I haven't proven the loop will always terminate. It may oscillate between two values differing in the last digit. Or it may not.

下壹個目標 2024-10-27 05:31:10

最好的方法可能是使用连分式扩展 [1; 2, 2, ...] 2 的平方根。

def root_two_cf_expansion():
    yield 1
    while True:
        yield 2

def z(a,b,c,d, contfrac):
    for x in contfrac:
        while a > 0 and b > 0 and c > 0 and d > 0:
            t = a // c
            t2 = b // d
            if not t == t2:
                break
            yield t
            a = (10 * (a - c*t))
            b = (10 * (b - d*t))
            # continue with same fraction, don't pull new x
        a, b = x*a+b, a
        c, d = x*c+d, c
    for digit in rdigits(a, c):
        yield digit

def rdigits(p, q):
    while p > 0:
        if p > q:
           d = p // q
           p = p - q * d
        else:
           d = (10 * p) // q
           p = 10 * p - q * d
        yield d

def decimal(contfrac):
    return z(1,0,0,1,contfrac)

decimal((root_two_cf_expansion()) 返回所有十进制数字的迭代器。算法中的 t1t2 是当它们相等时,我们输出该数字,

请注意,这不处理某些特殊情况,例如连分数中的负数

(此代码是 Haskell 代码的改编,用于处理浮动的连分数。 )

The nicest way is probably using the continued fraction expansion [1; 2, 2, ...] the square root of two.

def root_two_cf_expansion():
    yield 1
    while True:
        yield 2

def z(a,b,c,d, contfrac):
    for x in contfrac:
        while a > 0 and b > 0 and c > 0 and d > 0:
            t = a // c
            t2 = b // d
            if not t == t2:
                break
            yield t
            a = (10 * (a - c*t))
            b = (10 * (b - d*t))
            # continue with same fraction, don't pull new x
        a, b = x*a+b, a
        c, d = x*c+d, c
    for digit in rdigits(a, c):
        yield digit

def rdigits(p, q):
    while p > 0:
        if p > q:
           d = p // q
           p = p - q * d
        else:
           d = (10 * p) // q
           p = 10 * p - q * d
        yield d

def decimal(contfrac):
    return z(1,0,0,1,contfrac)

decimal((root_two_cf_expansion()) returns an iterator of all the decimal digits. t1 and t2 in the algorithm are minimum and maximum values of the next digit. When they are equal, we output that digit.

Note that this does not handle certain exceptional cases such as negative numbers in the continued fraction.

(This code is an adaptation of Haskell code for handling continued fractions that has been floating around.)

挽你眉间 2024-10-27 05:31:10

嗯,下面是我写的代码。它在大约 60800 秒内为我生成了 2 的平方根的小数点后一百万位数字,但我的笔记本电脑在运行该程序时正在休眠,它应该更快。您可以尝试生成 300 万个数字,但可能需要几天时间才能得到。

def sqrt(number,digits_after_decimal=20):
import time
start=time.time()
original_number=number
number=str(number)
list=[]
for a in range(len(number)):
    if number[a]=='.':
        decimal_point_locaiton=a
        break
    if a==len(number)-1:
        number+='.'
        decimal_point_locaiton=a+1
if decimal_point_locaiton/2!=round(decimal_point_locaiton/2):
    number='0'+number
    decimal_point_locaiton+=1
if len(number)/2!=round(len(number)/2):
    number+='0'
number=number[:decimal_point_locaiton]+number[decimal_point_locaiton+1:]
decimal_point_ans=int((decimal_point_locaiton-2)/2)+1
for a in range(0,len(number),2):
    if number[a]!='0':
        list.append(eval(number[a:a+2]))
    else:
        try:
            list.append(eval(number[a+1]))
        except IndexError:
            pass
p=0
c=list[0]
x=0
ans=''
for a in range(len(list)):
    while c>=(20*p+x)*(x):
        x+=1
    y=(20*p+x-1)*(x-1)
    p=p*10+x-1
    ans+=str(x-1)
    c-=y
    try:
        c=c*100+list[a+1]
    except IndexError:
        c=c*100
while c!=0:
    x=0
    while c>=(20*p+x)*(x):
        x+=1
    y=(20*p+x-1)*(x-1)
    p=p*10+x-1
    ans+=str(x-1)
    c-=y
    c=c*100
    if len(ans)-decimal_point_ans>=digits_after_decimal:
            break
ans=ans[:decimal_point_ans]+'.'+ans[decimal_point_ans:]
total=time.time()-start
return ans,total

Well, the following is the code that I wrote. It generated a million digits after the decimal for the square root of 2 in about 60800 seconds for me, but my laptop was sleeping when it was running the program, it should be faster that. You can try to generate 3 million digits, but it might take a couple days to get it.

def sqrt(number,digits_after_decimal=20):
import time
start=time.time()
original_number=number
number=str(number)
list=[]
for a in range(len(number)):
    if number[a]=='.':
        decimal_point_locaiton=a
        break
    if a==len(number)-1:
        number+='.'
        decimal_point_locaiton=a+1
if decimal_point_locaiton/2!=round(decimal_point_locaiton/2):
    number='0'+number
    decimal_point_locaiton+=1
if len(number)/2!=round(len(number)/2):
    number+='0'
number=number[:decimal_point_locaiton]+number[decimal_point_locaiton+1:]
decimal_point_ans=int((decimal_point_locaiton-2)/2)+1
for a in range(0,len(number),2):
    if number[a]!='0':
        list.append(eval(number[a:a+2]))
    else:
        try:
            list.append(eval(number[a+1]))
        except IndexError:
            pass
p=0
c=list[0]
x=0
ans=''
for a in range(len(list)):
    while c>=(20*p+x)*(x):
        x+=1
    y=(20*p+x-1)*(x-1)
    p=p*10+x-1
    ans+=str(x-1)
    c-=y
    try:
        c=c*100+list[a+1]
    except IndexError:
        c=c*100
while c!=0:
    x=0
    while c>=(20*p+x)*(x):
        x+=1
    y=(20*p+x-1)*(x-1)
    p=p*10+x-1
    ans+=str(x-1)
    c-=y
    c=c*100
    if len(ans)-decimal_point_ans>=digits_after_decimal:
            break
ans=ans[:decimal_point_ans]+'.'+ans[decimal_point_ans:]
total=time.time()-start
return ans,total
弥繁 2024-10-27 05:31:10

Python 已经支持开箱即用的大整数,如果这是使用 C/C++ 唯一阻碍您的因素,您始终可以自己编写一个快速容器类。

您提到的唯一问题是缺乏大整数。如果您不想为此使用库,那么您是否正在寻求编写此类课程的帮助?

Python already supports big integers out of the box, and if that's the only thing holding you back in C/C++ you can always write a quick container class yourself.

The only problem you've mentioned is a lack of big integers. If you don't want to use a library for that, then are you looking for help writing such a class?

北音执念 2024-10-27 05:31:10

这是一个更有效的整数平方根函数(在 Python 3.x 中),在所有情况下都应该终止。它从一个更接近平方根的数字开始,因此需要更少的步骤。请注意,int.bit_length 需要 Python 3.1+。为了简洁起见,省略了错误检查。

def isqrt(n):
    x = (n >> n.bit_length() // 2) + 1
    result = (x + n // x) // 2
    while abs(result - x) > 1:
        x = result
        result = (x + n // x) // 2
    while result * result > n:
        result -= 1
    return result

Here's a more efficient integer square root function (in Python 3.x) that should terminate in all cases. It starts with a number much closer to the square root, so it takes fewer steps. Note that int.bit_length requires Python 3.1+. Error checking left out for brevity.

def isqrt(n):
    x = (n >> n.bit_length() // 2) + 1
    result = (x + n // x) // 2
    while abs(result - x) > 1:
        x = result
        result = (x + n // x) // 2
    while result * result > n:
        result -= 1
    return result
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文