我试图在新的python3.8上运行一些测试,发现了^{
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)
总是产生{x*x
产生{比较:
对于这两对(分别是非常大和非常小的)输入,}则是灾难性的错误。在
hypot
做得很好,而{当原始版本}既不是很大也不是很小)时,它可能比函数{}的精度高或低,具体取决于}。它们都可以被期望产生一个与数学结果相差几微秒的结果。但由于它们是用不同方法得到的不同近似值,它们可能会有所不同(在最坏的情况下是“几个ULP”的两倍)。在
sqrt(x*x + y*y)
工作得相当好(当值x
和{x
和{hypot(x, y)
的一个典型实现是首先在必要时交换x
和{x
具有最大的幅值,然后计算x * sqrt(1 + (y/x)*(y/x))
。这解决了x*x
溢出的问题。作为一个副作用,这意味着即使没有溢出,结果也与sqrt(x*x + y*y)
略有不同。在注意,当您将}是小整数,},它们的和可以精确地计算为浮点值。如果这个和是整数的平方,浮点函数
sqrt(x*x + y*y)
应用于小整数时,sqrt(x*x + y*y)
更精确是正常的:当x
和{x*x
和{sqrt
只能计算这个整数。简而言之,在这种情况下,尽管计算是浮点的,但从头到尾都是精确的。相比之下,上面典型的hypot
实现是从计算x/y
(在您的测试中,95.0/168.0
)开始的,而这个结果通常不能完全表示为浮点值。第一步已经产生了一个近似值,这种近似值可能会导致最终结果错误(就像在您的测试中一样)!在对于}更精确,即使在{}工作的地方也是如此)。在
hypot
没有标准算法:它只需要计算数学表达式√(x2+y2)的良好近似值,同时避免溢出和下溢问题。This article显示了不同的实现,并指出我提到的流行实现牺牲了准确性以避免溢出和下溢(但是本文还为hypot
提供了一个浮点实现,它比{相关问题 更多 >
编程相关推荐