Неверный ответ при возведении переменной в степень 1/3 python

При выполнении кода

f=-1**(1/3)

Переменная f принимает значение -1 как и должно быть. Но в случае выполнения кода:

x=-1
f=x**(1/3)

Переменная f принимает значение (0.5000000000000001+0.8660254037844386j)

Подобное происходит и при других отрицательных значениях x
Например:

  • При x=-8
    (1.0000000000000002+1.7320508075688772j)
  • При x=-27
    (1.5000000000000004+2.598076211353316j)

Почему это происходит, и как это решать?


Ответы (4 шт):

Автор решения: Stanislav Volodarskiy

-1**(1/3)

Выражение -1**(1/3) разбирается компилятором как -(1**(1/3)) (6.5. The power operator):

Thus, in an unparenthesized sequence of power and unary operators, the operators are evaluated from right to left (this does not constrain the evaluation order for the operands): -1**2 results in -1.

Возведение в степень возвращает единицу, унарный минус превращает её в минус единицу.

x**(1/3)

Возведение в степень равносильно вызову pow (6.5. The power operator):

The power operator has the same semantics as the built-in pow() function, when called with two arguments: it yields its left argument raised to the power of its right argument.

В случае x=-1; f=x**(1/3) получается вызов pow(-1, 1 / 3). А так как вы возводите отрицательное число в вещественную (не целую) степень, то вычисляется комплексный корень (pow(base, exp, mod=None)):

For a negative base of type int or float and a non-integral exponent, a complex result is delivered.

Если нужно извлекать кубические корни без этих сложностей используйте math.cbrt:

@>>> import math
@>>> math.cbrt(-1)
-1.0
→ Ссылка
Автор решения: Fox Fox
import sympy
print(sympy.sign(-8) * sympy.Abs(-8) ** sympy.Rational(1, 3))

Результат: кубический корень из -8 равен -2. Вроде бы работает со всеми натуральными корнями, и с положительными, и с отрицательными числами.

→ Ссылка
Автор решения: CrazyElf

Раз уж тут упомянули sympy. В пространстве комплексных чисел есть три разных числа, которые при возведении в третью степень дают -1. Так что у числа -1 три кубических корня в комплексном пространстве.

from sympy import *

x = symbols('x')
solveset(x**3 + 1, x)

введите сюда описание изображения

Вот если ограничиться рациональными числами, то корень будет один:

solveset(x**3 + 1, x, domain=S.Reals)
# {−1}

Это просто пояснение, что картина с корнями вообще-то несколько шире, чем нам кажется из школьной арифметики.

→ Ссылка
Автор решения: Serge3leo

Собственно @StanislavVolodarskiy полностью ответил на поставленный вопрос.

Но принципиального решения этой задачи в общем виде - x в степени y, без костылей, похоже нет. Всё ещё хуже - выдаётся неправильный результат. Microsoft .Net по крайней мере хоть дурость не выдаёт в качестве результата

С точки зрения строгой компьютерной математики, IEC 60559 с давних пор строго определяет несколько функций:

  • squareRoot() (x**(1/2));
  • rSqrt() (x**(-1/2));
  • rootn() (x**(1/n));
  • pown() (x**n);
  • pow() (x**y);
  • powr() (exp(ln(x)*y)).

По вопросу требовалась функция rootn() (очевидно, по тексту вопроса имелось ввиду 1/3, а не 0.3333333333333333) и, к счастью, Python реализует её частный случай - math.cbrt() (наследство языка C).

А вот полная реализация функции rootn() вошла только в стандарт языка C23, будем надеяться, что когда-нибудь она войдёт и в Python. В принципе, её можно будет достать из новых libс/libm посредством ctype, но это не прям сейчас, в glibc её добавили только в мае 2025, за FreeBSD/macOS ещё не смотрел.

А пока же, для отрицательных x, pow() и x**(1/n) возвращает первый комплексный корень, а math.pow() - ошибку.

Numpy np.power() и x**(1/n), возвращает NaN.

Из популярных численных библиотек поддержка rootn() есть в gmpy2 (только для n > 0), а в православном mpmath следует использовать mpmath.root(x, n, n//2 if x < 0. and (n&1) else 0) (т.е. требуется указать номер требуемого действительного корня для нечётного n, зато n может быть отрицательным). У обеих библиотек нет полной поддержки IEC 60559 в части ошибок и ±∞.

→ Ссылка