파이썬에서 float에 대한 내장 pow ()와 math.pow ()의 차이점은 무엇입니까?
두 개의 float 인수 의 경우 Python의 내장 pow(x, y)
(세 번째 인수 없음) 에서 반환 된 결과 와에서 반환 된 값에 차이가 있습니까?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)는 x가 0이거나 NaN 인 경우에도 항상 1.0을 반환합니다. x와 y가 모두 유한하고 x는 음수이고 y가 정수가 아닌 경우 pow (x, y)는 정의되지 않고 ValueError를 발생시킵니다.
버전 2.6에서 변경 : 1 ** nan 및 nan ** 0의 결과가 정의되지 않았습니다.
마지막 줄에 유의하십시오. 문서는의 동작이 math.pow()
지수 연산자 **
(따라서의 pow(x, y)
) 동작임을 암시합니다 . 이것은 공식적으로 보장됩니까?
배경 : 내 목표의 구현을 제공하는 것입니다 모두 내장 pow()
과의 math.pow()
불확실성 숫자 가 같은 방식으로 동작 일반 파이썬 수레 (같은 수치 결과, 같은 예외 코너의 경우에 동일한 결과 등) 등. 나는 한 이미 구현 아주 잘 작동 뭔가를하지만, 일부가 코너의 경우 처리해야합니다.
빠른 확인
서명을 통해 서로 다르다는 것을 알 수 있습니다.
pow (x, y [, z])
math.pow (x, y)
또한 셸에서 시도하면 빠른 아이디어를 얻을 수 있습니다.
>>> 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()
. 이는 유연성을 희생합니다. 살펴 갖는 소스를 , 우리가 인수하는 것을 볼 수 math.pow()
있다 복식에 직접 캐스트 :
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);
/*...*/
그런 다음 유효성을 위해 복식에 대해 검사를 수행 한 다음 결과를 기본 C 수학 라이브러리로 전달합니다.
내장 pow()
반면에 내장 pow()
( **
연산자 와 동일 )은 매우 다르게 동작합니다. 실제로는 Objects 고유의 **
연산자 구현을 사용하며 , 필요한 경우 숫자의 __pow__()
, __rpow__()
또는 __ipow__()
, 메서드 를 대체하여 최종 사용자가 재정의 할 수 있습니다 .
For built-in types, it is instructive to study the difference between the power function implemented for two numeric types, for example, floats, long and complex.
Overridding the default behaviour
Emulating numeric types is described here. essentially, if you are creating a new type for numbers with uncertainty, what you will have to do is provide the __pow__()
, __rpow__()
and possibly __ipow__()
methods for your type. This will allow your numbers to be used with the operator:
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
)
In order to override math.pow()
you will have to monkey patch it to support your new type:
def new_pow(a,b):
_a = Uncertain(a)
_b = Uncertain(b)
return _a ** _b
math.pow = new_pow
Note that for this to work you'll have to wrangle the Uncertain
class to cope with an Uncertain
instance as an input to __init__()
math.pow()
implicitly converts its arguments to float
:
>>> from decimal import Decimal
>>> from fractions import Fraction
>>> math.pow(Fraction(1, 3), 2)
0.1111111111111111
>>> math.pow(Decimal(10), -1)
0.1
but the built-in pow
does not:
>>> pow(Fraction(1, 3), 2)
Fraction(1, 9)
>>> pow(Decimal(10), -1)
Decimal('0.1')
My goal is to provide an implementation of both the built-in pow() and of math.pow() for numbers with uncertainty
You can overload pow
and **
by defining __pow__
and __rpow__
methods for your class.
However, you can't overload math.pow
(without hacks like math.pow = pow
). You can make a class usable with math.pow
by defining a __float__
conversion, but then you'll lose the uncertainty attached to your numbers.
Python's standard pow
includes a simple hack that makes pow(2, 3, 2)
faster than (2 ** 3) % 2
(of course, you'll only notice that with large numbers).
Another big difference is how the two functions handle different input formats.
>>> 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
However, I have no idea why anyone would prefer math.pow
over pow
.
Just adding %timeit comparison
In [1]: def pair_generator():
...: yield (random.random()*10, random.random()*10)
...:
In [2]: %timeit [a**b for a, b in pair_generator()]
538 ns ± 1.94 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [3]: %timeit [math.pow(a, b) for a, b in pair_generator()]
632 ns ± 2.77 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
'developer tip' 카테고리의 다른 글
HTML5 속성을 인용합니까? (0) | 2020.11.28 |
---|---|
파이썬의 제네릭 / 템플릿? (0) | 2020.11.28 |
템플릿을 사용하여 람다를 std :: function으로 변환하는 방법 (0) | 2020.11.28 |
.svn 폴더 크기 줄이기 (0) | 2020.11.28 |
OpenLayers 3으로 마커를 추가하는 방법 (0) | 2020.11.28 |