Неверный ответ при возведении переменной в степень 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 шт):
-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**2results 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
intorfloatand a non-integral exponent, a complex result is delivered.
Если нужно извлекать кубические корни без этих сложностей используйте math.cbrt:
@>>> import math @>>> math.cbrt(-1) -1.0
import sympy
print(sympy.sign(-8) * sympy.Abs(-8) ** sympy.Rational(1, 3))
Результат: кубический корень из -8 равен -2. Вроде бы работает со всеми натуральными корнями, и с положительными, и с отрицательными числами.
Раз уж тут упомянули sympy. В пространстве комплексных чисел есть три разных числа, которые при возведении в третью степень дают -1. Так что у числа -1 три кубических корня в комплексном пространстве.
from sympy import *
x = symbols('x')
solveset(x**3 + 1, x)
Вот если ограничиться рациональными числами, то корень будет один:
solveset(x**3 + 1, x, domain=S.Reals)
# {−1}
Это просто пояснение, что картина с корнями вообще-то несколько шире, чем нам кажется из школьной арифметики.
Собственно @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 в части ошибок и ±∞.
