内置的pow()和math.pow()为浮动,在Python中的区别?

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

我问这个问题,因为math.pow()的文档意味着pow(x, y) (即x**y )与math.pow(x, y)基本相同:

math.pow(x,y)

把x提升到y的力量。 例外情况应尽可能遵循C99标准的附件“F”。 特别是,pow(1.0,x)和pow(x,0.0)总是返回1.0,即使x是零或NaN。 如果x和y都是有限的,x是负数,y不是一个整数,那么pow(x,y)是未定义的,并引发ValueError。

在版本2.6中改变:1 ** nan和nan ** 0的结果是不确定的。

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

背景:我的目标是提供一个内置pow()math.pow()实现,用于处理不确定性的数字, 其行为与常规Python浮点数相同(相同的数字结果,相同的例外,相同的结果对于angular落案件等)。 我已经实现了一些很好的工作,但是还有一些需要处理的问题。

快速检查

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

pow(x,y [,z])

math.pow(x,y)

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

 >>> pow is math.pow False 

testing差异

了解这两种function之间的行为差​​异的另一种方法是testing它们:

 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 

还有其他的区别,上面的testing列表并不完整(没有很长的数字,也没有复杂的等等),但是这会给我们一个实用的清单,告诉我们这两个函数的行为有什么不同。 我也build议扩展上面的testing来检查每个函数返回的types。 你也许可以写一些类似的东西来创build两个函数之间差异的报告。

math.pow()

math.pow()处理它的参数与内build**pow()非常不同。 这是以灵活性为代价的。 看看源代码 ,我们可以看到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); /*...*/ 

然后对双打进行有效性检查,然后将结果传递给底层的Cmath库。

内buildpow()

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

对于内置types,研究实现两种数字types(例如浮点数 , 长和复数)的幂函数之间的差异是有益的 。

覆盖默认行为

这里描述了模拟数字types。 本质上来说,如果你为不确定的数字创build一个新的types,你将不得不为你的types提供__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( ((Bx*(Ax**(Bx-1)))**2)*A.delta*A.delta + (((Ax**Bx)*math.log(Bx))**2)*B.delta*B.delta ) 

为了覆盖math.pow()你将不得不为猴子补丁来支持你的新types:

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

注意,为了这个工作,你必须把Uncertain类作为__init__()的input来处理,

math.pow()将其参数隐式转换为float

 >>> math.pow(Fraction(1, 3), 2) 0.1111111111111111 >>> math.pow(Decimal(10), -1) 0.1 

但是内置的pow不会:

 >>> pow(Fraction(1, 3), 2) Fraction(1, 9) >>> pow(Decimal(10), -1) Decimal('0.1') 

我的目标是为具有不确定性的数字提供内置的pow()和math.pow()的实现

你可以通过为你的类定义__pow____rpow__方法来重载pow**

但是,你不能超载math.pow (没有math.pow = powmath.pow = pow )。 你可以通过定义一个__float__转换来使一个类可以使用math.pow ,但是这样你将失去数字的不确定性。

Python的标准function包括一个简单的hack,使pow(2, 3, 2)(2 ** 3) % 2快(当然,你只会注意到大数字)。

另一个很大的区别是两个函数如何处理不同的input格式。

 >>> pow(2, 1+0.5j) (1.8810842093664877+0.679354250205337j) >>> math.pow(2, 1+0.5j) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't convert complex to float 

不过,我不知道为什么有人会喜欢math.pow over pow