Разница между встроенным pow () и математикой.pow() для поплавков, в Python?


есть ли разница в результатах, возвращаемых встроенным Python pow(x, y) (нет третьего аргумента) и значения, возвращаемые math.pow() в случае двух float аргументов.

Я задаю этот вопрос, потому что документация на math.pow() означает, что pow(x, y) (т. е. x**y) по сути то же самое, что math.pow(x, y):

математика.pow (x, y)

возвращает X в степени у. Исключительные ситуации насколько это возможно, следуйте приложению " F " к стандарту С99. В в частности, pow (1.0, x) и pow (x, 0.0) всегда возвращают 1.0, даже если x это ноль или НАН. Если и x, и y конечны, то x отрицательно, а y не является целым числом, тогда pow (x, y) не определен и вызывает ValueError.

изменено в версии 2.6: результат 1 * * nan и nan* * 0 не был определен.

обратите внимание на последнюю строку: документация подразумевает, что поведение math.pow() is что оператора возведения в степень ** (и, следовательно,pow(x, y)). Это официально гарантировано?

Предыстория: моя цель-обеспечить реализацию и встроенный pow() и math.pow() для чисел с неопределенностью что ведет себя точно так же как и с обычными Python поплавками (те же численные результаты, те же исключения, те же результаты для угловых случаев и т. д.). У меня есть уже реализовано то, что работает вполне хорошо, но есть некоторые случаи, которые должны быть обработаны.

3 56

3 ответа:

Быстрая Регистрация

по подписям можно сказать, что они разные:

pow (x, y[, z])

математика.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() are бросьте сразу к двойникам:

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 math.

builtin pow()

встроенный pow() (то же самое, что ** оператор) с другой стороны ведет себя совсем по-другому, он фактически использует собственную реализацию объектов ** оператор, который может быть переопределен конечным пользователем, если это необходимо, заменив число __pow__(),__rpow__() или __ipow__(), способ.

для встроенных типов полезно изучить разницу между функцией мощности, реализованной для двух числовых типов, для например, терки,долго и комплекс.

переопределение поведения по умолчанию

описана эмуляция числовых типов здесь. по сути, если вы создаете новый тип для чисел с неопределенностью, то вам нужно будет предоставить __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
    )

In чтобы переопределить math.pow() вы должны будете обезьяна патч его для поддержки вашего нового типа:

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

math.pow = new_pow

обратите внимание, что для этого вам придется спорить Uncertain класс, чтобы справиться с Uncertain экземпляр в качестве входных данных для __init__()

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 и ** определение __pow__ и __rpow__ методы для вашего класса.

однако, вы не можете перегрузить math.pow (без хаков, как math.pow = pow). Вы можете сделать класс пригодным для использования с math.pow определение __float__ преобразование, но тогда вы потеряете неопределенность, связанную с вашими номерами.

питон pow включает в себя простой хак, который делает pow(2, 3, 2) быстрее (2 ** 3) % 2 (конечно, вы заметите это только с большими числами).

еще одна большая разница заключается в том, как эти две функции обрабатывают разные форматы ввода.

>>> 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.