python - 为什么在 Python 3.8 中是 sqrt(x*x + y*y) != math.hypot(x, y)?

标签 python math floating-point python-3.8

我正在尝试在 Shiny 的新 Python 3.8 上运行一些测试并注意到 math.hypot 的一个问题.从文档:

For a two dimensional point (x, y), this is equivalent to computing the hypotenuse of a right triangle using the Pythagorean theorem, sqrt(x*x + y*y).



但是,这些在 3.8 中并不等效:
>>> from math import hypot, sqrt
>>> x, y = 95, 168
>>> sqrt(x*x + y*y), hypot(x, y), sqrt(x*x + y*y) == hypot(x, y)
(193.0, 193.00000000000003, False)
>>> sqrt(x*x + y*y).is_integer(), hypot(x, y).is_integer()
(True, False)

在 3.7 中,两种方式产生完全相同的结果( "193.0" ,它被认为是一个整数)。

最佳答案

函数hypot提供 另一个 数学表达式√(x2 + y2)的近似值,就像浮点表达式sqrt(x*x + y*y)是这个相同数学表达式的近似值。

函数hypot推荐使用它,因为它解决了浮点计算中存在的非常明显的缺陷 sqrt(x*x + y*y)具有非常大或非常小的值。例如,如果 x仅比最大有限浮点值的平方根大一点,sqrt(x*x + y*y)总是产生 +inf因为 x*x生产 +inf .

相比:

>>> x, y = 95E200, 168E200
>>> sqrt(x*x + y*y), hypot(x, y)
(inf, 1.93e+202)
>>> z, t = 95E-200, 168E-200
>>> sqrt(z*z + t*t), hypot(z, t)
(0.0, 1.93e-198)

对于这两对(分别是非常大和非常小的)输入,hypot做得很好,而 sqrt(x*x + y*y)是灾难性的错误。

当幼稚版sqrt(x*x + y*y)工作得相当好(当值 xy 既不是很大也不是很小时),它可能比函数 hypot 更准确或更不准确。取决于 x 的值和 y .预计它们都会产生与数学结果相差几个 ULP 的结果。但是由于它们是通过不同方法获得的不同近似值,因此它们可能会有所不同(在最坏的情况下是“几个 ULP”的两倍)。
hypot(x, y)的一种典型实现第一个交换xy如有必要,以便 x具有最大的震级,然后计算 x * sqrt(1 + (y/x)*(y/x)) .这解决了 x*x 的问题溢出。作为副作用,这意味着 即使没有溢出 ,结果与sqrt(x*x + y*y)略有不同.

请注意,sqrt(x*x + y*y) 是正常的当您将其应用于小整数时(就像您在测试中所做的那样)更精确:当 xy是小整数,x*xy*y它们的总和可以精确地计算为浮点值。如果此和是整数的平方,则浮点函数 sqrt只能计算这个整数。简而言之,在这种情况下,尽管是浮点计算,但从头到尾都是精确的。相比之下,典型的hypot上面的实现从计算 x/y 开始(在您的测试中, 95.0/168.0 ),并且此结果通常不能完全表示为浮点值。第一步已经产生了一个近似值,这个近似值可能导致最终结果是错误的(就像在你的测试中一样)!
hypot没有标准算法:只期望计算数学表达式 √(x2 + y2) 的良好近似,同时避免上溢和下溢问题。 This article展示了不同的实现,并指出我提到的流行实现牺牲了准确性以避免上溢和下溢(但文章还提供了 hypot 的浮点实现,即 更准确 sqrt(x*x + y*y)即使在 sqrt(x*x + y*y) 工作的地方)。

关于python - 为什么在 Python 3.8 中是 sqrt(x*x + y*y) != math.hypot(x, y)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58397779/

相关文章:

python - 如何计算多个csv文件中的行数

python - Discord 机器人可以存储信息的地方在哪里 [discord.py]

python 套接字和 epoll

json - 通过 jq 从字符串中解析浮点值

python - "Non-equal"或 "greater than"更快?

java - 查找两个大整数的 SHA-1 哈希值并将其作为字符串返回的正确方法

math - 高级矩形碰撞处理

javascript - 正则表达式实现负号的奇偶规则

floating-point - fabs(double)如何在x86上实现?这是一项昂贵的手术吗?

c++ - 我正在尝试计算这个连分数,但我似乎无法工作,但是该程序可以正确编译但在工作时崩溃