gpt4 book ai didi

python - Python 中用于 float 的内置 pow() 和 math.pow() 之间的区别?

转载 作者:IT老高 更新时间:2023-10-28 21:44:49 27 4
gpt4 key购买 nike

Python内置的pow(x, y)(没有第三个参数)返回的结果和math.pow()返回的值有区别吗>,在两个 float 参数的情况下。

我问这个问题是因为 documentation对于 math.pow() 意味着 pow(x, y) (即 x**y)本质上与 相同数学.pow(x, y):

math.pow(x, y)

Return x raised to the power y. Exceptional cases follow Annex ‘F’ of the C99 standard as far as possible. In particular, pow(1.0, x) and pow(x, 0.0) always return 1.0, even when x is a zero or a NaN. If both x and y are finite, x is negative, and y is not an integer then pow(x, y) is undefined, and raises ValueError.

Changed in version 2.6: The outcome of 1**nan and nan**0 was undefined.

注意最后一行:文档暗示 math.pow() 的行为是指数运算符 ** 的行为(因此 pow (x, y))。这是官方保证的吗?

背景:我的目标是提供 both 内置 pow()math.pow() 的实现具有不确定性的数字 其行为方式与常规 Python float 相同(相同的数值结果、相同的异常、极端情况下的相同结果等)。我有 already implemented效果很好的东西,但有一些 corner cases需要处理。

最佳答案

快速检查

从签名中,我们可以看出它们是不同的:

pow(x, y[, z])

math.pow(x, y)

另外,在 shell 中尝试一下会给你一个快速的想法:

>>> pow is math.pow
False

测试差异

了解两个函数之间行为差异的另一种方法是测试它们:

import math
import traceback
import sys

inf = float("inf")
NaN = float("nan")

vals = [inf, NaN, 0.0, 1.0, 2.2, -1.0, -0.0, -2.2, -inf, 1, 0, 2]

tests = set([])

for vala in vals:
for valb in vals:
tests.add( (vala, valb) )
tests.add( (valb, vala) )


for a,b in tests:
print("math.pow(%f,%f)"%(a,b) )
try:
print(" %f "%math.pow(a,b))
except:
traceback.print_exc()

print("__builtins__.pow(%f,%f)"%(a,b) )
try:
print(" %f "%__builtins__.pow(a,b))
except:
traceback.print_exc()

然后我们可以注意到一些细微的差异。例如:

math.pow(0.000000,-2.200000)
ValueError: math domain error

__builtins__.pow(0.000000,-2.200000)
ZeroDivisionError: 0.0 cannot be raised to a negative power

还有其他区别,上面的测试列表并不完整(没有长数字,没有复杂等等),但这会给我们一个实用的列表,说明这两个函数的行为方式有何不同。我还建议扩展上述测试以检查每个函数返回的类型。您可能可以编写类似的东西来创建两个函数之间差异的报告。

math.pow()

math.pow() 处理其参数的方式与内置 **pow() 非常不同。这是以灵 active 为代价的。看看the source ,我们可以看到 math.pow() 的参数是直接转换为 double :

static PyObject *
math_pow(PyObject *self, PyObject *args)
{
PyObject *ox, *oy;
double r, x, y;
int odd_y;

if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
return NULL;
x = PyFloat_AsDouble(ox);
y = PyFloat_AsDouble(oy);
/*...*/

然后对 double 进行有效性检查,然后将结果传递给底层 C 数学库。

内置 pow()

另一方面,内置的 pow()(与 ** 运算符相同)的行为非常不同,它实际上使用了对象自己的 ** 运算符,如果需要,最终用户可以通过替换数字的 __pow__()__rpow__() 来覆盖它__ipow__(),方法。

对于内置类型,研究为两种数值类型实现的幂函数之间的差异是有益的,例如,floats , longcomplex .

覆盖默认行为

描述了模拟数字类型here .本质上,如果您要为不确定的数字创建新类型,您需要做的是提供 __pow__()__rpow__() 和可能的 __ipow__ () 方法为您的类型。这将允许您的号码与运营商一起使用:

class Uncertain:
def __init__(self, x, delta=0):
self.delta = delta
self.x = x
def __pow__(self, other):
return Uncertain(
self.x**other.x,
Uncertain._propagate_power(self, other)
)
@staticmethod
def _propagate_power(A, B):
return math.sqrt(
((B.x*(A.x**(B.x-1)))**2)*A.delta*A.delta +
(((A.x**B.x)*math.log(B.x))**2)*B.delta*B.delta
)

为了覆盖 math.pow(),您必须对其进行修补以支持您的新类型:

def new_pow(a,b):
_a = Uncertain(a)
_b = Uncertain(b)
return _a ** _b

math.pow = new_pow

请注意,要使其正常工作,您必须处理 Uncertain 类以处理 Uncertain 实例作为 __init__()

关于python - Python 中用于 float 的内置 pow() 和 math.pow() 之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10282674/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com