内置的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 = pow
像math.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
。