3phpmpom

3phpmpom1#

选项1:第一个月

标准库中的math模块有一个sqrt函数来计算一个数的平方根,它接受can be converted to float(包括int)作为参数,并返回一个float

>>> import math
>>> math.sqrt(9)
3.0

选项2:分数指数

幂运算符(**)或内置的pow()函数也可以用来计算平方根。
幂运算符需要数值类型,并且与二进制算术运算符的转换规则匹配,因此在这种情况下,它将返回floatcomplex数字。

>>> 9 ** (1/2)
3.0
>>> 9 ** .5  # Same thing
3.0
>>> 2 ** .5
1.4142135623730951

(Note:在Python 2中,1/2被截断为0,所以你必须用1.0/2或类似的来强制浮点运算。
这种方法可以推广到nth root,尽管不能精确表示为float的分数(如1/3或任何不是2的幂的分母)可能会导致一些不准确:

>>> 8 ** (1/3)
2.0
>>> 125 ** (1/3)
4.999999999999999

边缘案例

阴性和复杂

指数运算适用于负数和复数,尽管结果有一些轻微的误差:

>>> (-25) ** .5  # Should be 5j
(3.061616997868383e-16+5j)
>>> 8j ** .5  # Should be 2+2j
(2.0000000000000004+2j)

注意-25上的括号!否则它会被解析为-(25**.5),因为求幂比一元求反更紧密地绑定。
同时,math只为浮点数构建,所以对于x<0math.sqrt(x)将使ValueError: math domain error自乘,对于复数x,它将使TypeError: can't convert complex to float自乘,相反,您可以使用cmath.sqrt(x),它比求幂更精确(也可能更快):

>>> import cmath
>>> cmath.sqrt(-25)
5j
>>> cmath.sqrt(8j)
(2+2j)

精密度

这两个选项都涉及到到float的隐式转换,因此floating point precision is a factor。例如:

>>> n = 10**30
>>> x = n**2
>>> root = x**.5
>>> n == root
False
>>> n - root  # how far off are they?
0.0
>>> int(root) - n  # how far off is the float from the int?
19884624838656

非常大的数字甚至可能不适合一个浮点数,你会得到OverflowError: int too large to convert to float

其他类型

让我们以Decimal为例:
除非指数也是Decimal,否则求幂失败:

>>> decimal.Decimal('9') ** .5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ** or pow(): 'decimal.Decimal' and 'float'
>>> decimal.Decimal('9') ** decimal.Decimal('.5')
Decimal('3.000000000000000000000000000')

同时,mathcmath会将它们的参数分别静默地转换为floatcomplex,这可能意味着精度损失。
decimal也有自己的.sqrt()。另请参见calculating n-th roots using Python 3's decimal module

yr9zkbsy

yr9zkbsy2#

象征

根据您的目标,尽可能长时间地延迟平方根的计算可能是一个好主意。SymPy可能会有所帮助。
SymPy是一个用于符号数学的Python库。

import sympy
sympy.sqrt(2)
# => sqrt(2)

一开始看起来没什么用。
但sympy可以给予比浮点数或Decimal更多的信息:

sympy.sqrt(8) / sympy.sqrt(27)
# => 2*sqrt(6)/9

同样,精度也不会丢失。(√2)²仍然是整数:

s = sympy.sqrt(2)
s**2
# => 2
type(s**2)
#=> <class 'sympy.core.numbers.Integer'>

相比之下,float和Decimals将返回非常接近2但不等于2的数字:

(2**0.5)**2
# => 2.0000000000000004

from decimal import Decimal
(Decimal('2')**Decimal('0.5'))**Decimal('2')
# => Decimal('1.999999999999999999999999999')

Symy还可以理解更复杂的示例,如the Gaussian integral

from sympy import Symbol, integrate, pi, sqrt, exp, oo
x = Symbol('x')
integrate(exp(-x**2), (x, -oo, oo))
# => sqrt(pi)
integrate(exp(-x**2), (x, -oo, oo)) == sqrt(pi)
# => True

最后,如果需要十进制表示法,可以要求比实际需要更多的位数:

sympy.N(sympy.sqrt(2), 1_000_000)
# => 1.4142135623730950488016...........2044193016904841204
ryevplcw

ryevplcw3#

编号

>>> import numpy as np
>>> np.sqrt(25)
5.0
>>> np.sqrt([2, 3, 4])
array([1.41421356, 1.73205081, 2.        ])

docs

阴性

对于负实数,它将返回nan,因此np.emath.sqrt()在这种情况下可用。

>>> a = np.array([4, -1, np.inf])
>>> np.sqrt(a)
<stdin>:1: RuntimeWarning: invalid value encountered in sqrt
array([ 2., nan, inf])
>>> np.emath.sqrt(a)
array([ 2.+0.j,  0.+1.j, inf+0.j])

当然,另一种选择是先转换为复数:

>>> a = a.astype(complex)
>>> np.sqrt(a)
array([ 2.+0.j,  0.+1.j, inf+0.j])
jmo0nnb3

jmo0nnb34#

牛顿法
计算平方根最简单和最精确的方法是牛顿法。
你有一个数字,你想计算它的平方根(num),你有一个猜测的平方根(estimate)。估计可以是任何大于0的数字,但一个有意义的数字会大大缩短递归调用的深度。

new_estimate = (estimate + num/estimate) / 2

这一行使用这两个参数计算更精确的估计值。您可以将new_estimate值传递给函数并计算另一个new_estimate,它比前一个更精确,或者您可以像这样定义递归函数。

def newtons_method(num, estimate):
    # Computing a new_estimate
    new_estimate = (estimate + num/estimate) / 2
    print(new_estimate)
    # Base Case: Comparing our estimate with built-in functions value
    if new_estimate == math.sqrt(num):
        return True
    else:
        return newtons_method(num, new_estimate)

例如,我们需要求30的平方根,我们知道结果在5和6之间。

newtons_method(30,5)

数字为30,估计值为5。每个递归调用的结果为:

5.5
5.477272727272727
5.4772255752546215
5.477225575051661

最后一个结果是number的平方根的最精确计算,它与内置函数math.sqrt()的值相同。

vuv7lop3

vuv7lop35#

Python的fractions模块和它的类Fraction实现了有理数的算术运算。Fraction类没有实现平方根运算,因为大多数平方根都是无理数。但是,它可以用来近似任意精度的平方根,因为Fraction的分子和分母都是任意精度的整数。
下面的方法采用正数x和迭代次数,并返回x平方根的上界和下界。

from fractions import Fraction

def sqrt(x, n):
    x = x if isinstance(x, Fraction) else Fraction(x)
    upper = x + 1
    for i in range(0, n):
        upper = (upper + x/upper) / 2
    lower = x / upper
    if lower > upper:
        raise ValueError("Sanity check failed")
    return (lower, upper)

有关此操作实现的详细信息,请参阅下面的参考,它还显示了如何实现其他具有上界和下界的操作(尽管log操作显然至少有一个错误)。

  • Daumas,M.、Lester,D.、Muñoz,C.,"验证的实数计算:区间运算的库",arXiv:0708.3721 [cs. MS],2007年。

或者,使用Python的math.isqrt,我们可以计算任意精度的平方根:

  • i的平方根在正确值的1/2 * n * 范围内,其中i是整数:x1米10英寸1x.
  • i的平方根在正确值的1/10 * n * 范围内,其中i是整数:Fraction(math.isqrt(i * 10**(n*2)), 10**n)的数据。
  • x的平方根在正确值的1/2 * n * 范围内,其中x是1/2 * n * 的倍数:Fraction(math.isqrt(x * 2**(n)), 2**n).
  • x的平方根在正确值的1/10 * n * 范围内,其中x是1/10 * n * 的倍数:Fraction(math.isqrt(x * 10**(n)), 10**n).

在上述中,ix必须是0或更大。

hgtggwj0

hgtggwj06#

二进制搜索

    • 免责声明:**这是一个更专业的用例。此方法可能不适用于所有情况。

好处:

  • 可以查找整数值(即哪个整数是根?)
  • 不需要转换为浮点型,因此精度更高(也可以做得更好)

我个人为一个加密CTF挑战(RSA立方根攻击)实现了这个,在这个挑战中我需要一个精确的整数值。
一般的想法可以延伸到任何其他的根源。

def int_squareroot(d: int) -> tuple[int, bool]:
    """Try calculating integer squareroot and return if it's exact"""
    left, right = 1, (d+1)//2
    while left<right-1:
        x = (left+right)//2
        if x**2 > d:
            left, right = left, x
        else:
            left, right = x, right
    return left, left**2==d

编辑:

正如@wjandrea所指出的,这个示例代码不能计算。这是它没有将任何内容转换为浮点数的副作用,因此不会丢失精度。如果根是整数,则将其返回。如果不是,你会得到平方小于你的数的最大数。我更新了代码,这样它也会返回一个bool来指示值是否正确,并且修正了一个导致无限循环的问题(@wjandrea也指出了这一点)。这种通用方法的实现对于较小的数字仍然工作得有点奇怪,但超过10我就没有问题了。

克服此方法/实现的问题和限制:

对于较小的数字,你可以使用其他答案中的所有方法。他们通常使用浮点数,这 * 可能 * 会损失精度,但对于小整数,这应该意味着没有任何问题。所有使用浮点数的方法都有相同(或几乎相同)的限制。
如果你仍然想使用这个方法并得到浮点结果,那么把它转换成使用浮点也是很容易的。注意,这将重新引入精度损失,这是这个方法相对于其他方法的独特优点,在这种情况下,你也可以只使用任何其他的答案。我认为牛顿方法的版本收敛得更快一些,但我不确定。
对于较大的数字,浮点数会损失精度,这个方法可以给出更接近实际结果的结果(取决于输入的大小)。如果你想处理这个范围内的非整数,你可以使用其他类型,例如固定精度的数字。

编辑2,关于其他答案:

目前,afaik,唯一的其他答案,有类似或更好的精度为大数比这个实现是一个建议SymPy,由埃里克Duminil。该版本也更容易使用,并为任何类型的数字工作,唯一的缺点是,它需要SymPy。我的实现是免费的任何巨大的依赖性,如果这是你正在寻找的。

8ehkhllq

8ehkhllq7#

任意精度平方根

这个变体使用字符串操作将表示十进制浮点数的字符串转换为int,调用math.isqrt来执行实际的平方根提取,然后将结果格式化为十进制字符串。math.isqrt向下舍入,因此所有生成的数字都是正确的。
输入字符串num必须使用纯浮点格式:不支持“e”表示法。num字符串可以是纯整数,并且忽略前导零。
digits参数指定结果字符串中的小数位数,即小数点后的位数。

from math import isqrt

def str_sqrt(num, digits):
    """ Arbitrary precision square root

        num arg must be a string
        Return a string with `digits` after
        the decimal point

        Written by PM 2Ring 2022.01.26
    """

    int_part , _, frac_part = num.partition('.')
    num = int_part + frac_part

    # Determine the required precision
    width = 2 * digits - len(frac_part)

    # Truncate or pad with zeroes
    num = num[:width] if width < 0 else num + '0' * width
    s = str(isqrt(int(num)))

    if digits:
        # Pad, if necessary
        s = '0' * (1 + digits - len(s)) + s
        s = f"{s[:-digits]}.{s[-digits:]}"
    return s
测试
print(str_sqrt("2.0", 30))
输出
1.414213562373095048801688724209

对于小数位数,使用decimal.Decimal.sqrt会更快一些,大约32位数时,str_sqrt的速度与Decimal.sqrt大致相同,但对于128位数时,str_sqrtDecimal.sqrt快2.2倍,对于512位数时,str_sqrtDecimal.sqrt快4.3倍,对于8192位数时,str_sqrtDecimal.sqrt快7.4倍。
这是一个运行在SageMathCell服务器上的live version

yyhrrdl8

yyhrrdl88#

在python3中,你可以用下面的代码计算任意精度的平方根:

#SQUARE ROOT ANY PRECISION
from num7 import Num

n = Num('3.0')
root = n.sqrt(40) #set 40 digits after decimal point
print(root) #1.7320508075688772935274463415058723669428

文档链接:https://pypi.org/project/num7/https://github.com/giocip/num7

knsnq2tg

knsnq2tg9#

求一个数的平方根

while True:
    num = int(input("Enter a number:\n>>"))
    for i in range(2, num):
        if num % i == 0:
            if i*i == num:
                print("Square root of", num, "==>", i)
                break
    else:
        kd = (num**0.5)  # (num**(1/2))
        print("Square root of", num, "==>", kd)

输出:-
输入一个数字:24
24的平方根==〉4.898979485566356
输入一个数字:36
36的平方根==〉6
输入一个数字:49
49的平方根==〉7

✔💡点击下面的输出并查看✔

相关问题