Ambiguity in basic arithmetic operations Python [duplicate] - python

This question already has answers here:
ValueError: negative number cannot be raised to a fractional power
(2 answers)
Closed 5 years ago.
Here is the scenario:
In [5]: (2.0 - 5.0**(0.5)) ** (1.0/3.0)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-5-d064023f1ac5> in <module>()
----> 1 (2.0 - 5.0**(0.5)) ** (1.0/3.0)
ValueError: negative number cannot be raised to a fractional power
In [7]: -1.0 ** (1.0/3.0)
Out[7]: -1.0
The above operation is being done on a python interpreter. For the first expression, it is giving value error and says that negative number can't have fractional power !! So, firstly, why is this error as obviously, -ve numbers can have cube root or fifth root etc. Also, if that is the case, it should be consistent while in second case, it gives no error when -1 is raised to fractional power (1/3).
Can someone explain why is this the case?

The ** operator has specific binding behaviour; from the power operator documentation:
The power operator binds more tightly than unary operators on its left; it binds less tightly than unary operators on its right.
[...]
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.
So your second example is executed as:
-(1.0 ** (1.0/3.0))
That is to say, the - unary operator applies to the result of ** as that operator binds more tightly. As a result you have positive number is raised to the power 1/3rd, and only then made negative.
In your first example, the expression is parsed as
(2.0 - (5.0**(0.5))) ** (1.0/3.0)
There is no unary operator here, but the ** power operator does have a higher precedence than the binary - subtraction operator.
This then resolves as
(2.0 - 2.23606797749979) ** (1.0/3.0)
which is
(-0.2360679774997898) ** (1.0/3.0)
so is trying to raise a negative number to a fraction.
Python 2 ** (and the pow() function) don't support producing a complex number support when the inputs are at most float objects. Convert your negative float value to a complex() number first:
>>> (-1.0) ** 0.5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: negative number cannot be raised to a fractional power
>>> (-1+0j) ** 0.5
(6.123233995736766e-17+1j)
>>> (2+0j - 5.0**(0.5)) ** (1.0/3.0)
(0.30901699437494756+0.535233134659635j)
This changed in Python 3, where a complex result is returned for a negative number raised to a fractional power.

Related

How do I calculate square root in Python?

I need to calculate the square root of some numbers, for example √9 = 3 and √2 = 1.4142. How can I do it in Python?
The inputs will probably be all positive integers, and relatively small (say less than a billion), but just in case they're not, is there anything that might break?
Related
Integer square root in python
How to find integer nth roots?
Is there a short-hand for nth root of x in Python?
Difference between **(1/2), math.sqrt and cmath.sqrt?
Why is math.sqrt() incorrect for large numbers?
Python sqrt limit for very large numbers?
Which is faster in Python: x**.5 or math.sqrt(x)?
Why does Python give the "wrong" answer for square root? (specific to Python 2)
calculating n-th roots using Python 3's decimal module
How can I take the square root of -1 using python? (focused on NumPy)
Arbitrary precision of square roots
Note: This is an attempt at a canonical question after a discussion on Meta about an existing question with the same title.
Option 1: math.sqrt()
The math module from the standard library has a sqrt function to calculate the square root of a number. It takes any type that can be converted to float (which includes int) as an argument and returns a float.
>>> import math
>>> math.sqrt(9)
3.0
Option 2: Fractional exponent
The power operator (**) or the built-in pow() function can also be used to calculate a square root. Mathematically speaking, the square root of a equals a to the power of 1/2.
The power operator requires numeric types and matches the conversion rules for binary arithmetic operators, so in this case it will return either a float or a complex number.
>>> 9 ** (1/2)
3.0
>>> 9 ** .5 # Same thing
3.0
>>> 2 ** .5
1.4142135623730951
(Note: in Python 2, 1/2 is truncated to 0, so you have to force floating point arithmetic with 1.0/2 or similar. See Why does Python give the "wrong" answer for square root?)
This method can be generalized to nth root, though fractions that can't be exactly represented as a float (like 1/3 or any denominator that's not a power of 2) may cause some inaccuracy:
>>> 8 ** (1/3)
2.0
>>> 125 ** (1/3)
4.999999999999999
Edge cases
Negative and complex
Exponentiation works with negative numbers and complex numbers, though the results have some slight inaccuracy:
>>> (-25) ** .5 # Should be 5j
(3.061616997868383e-16+5j)
>>> 8j ** .5 # Should be 2+2j
(2.0000000000000004+2j)
Note the parentheses on -25! Otherwise it's parsed as -(25**.5) because exponentiation is more tightly binding than unary negation.
Meanwhile, math is only built for floats, so for x<0, math.sqrt(x) will raise ValueError: math domain error and for complex x, it'll raise TypeError: can't convert complex to float. Instead, you can use cmath.sqrt(x), which is more more accurate than exponentiation (and will likely be faster too):
>>> import cmath
>>> cmath.sqrt(-25)
5j
>>> cmath.sqrt(8j)
(2+2j)
Precision
Both options involve an implicit conversion to float, so floating point precision is a factor. For example:
>>> n = 10**30
>>> x = n**2
>>> root = x**.5
>>> n == root
False
>>> n - root # how far off are they?
0.0
>>> int(root) - n # how far off is the float from the int?
19884624838656
Very large numbers might not even fit in a float and you'll get OverflowError: int too large to convert to float. See Python sqrt limit for very large numbers?
Other types
Let's look at Decimal for example:
Exponentiation fails unless the exponent is also Decimal:
>>> decimal.Decimal('9') ** .5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ** or pow(): 'decimal.Decimal' and 'float'
>>> decimal.Decimal('9') ** decimal.Decimal('.5')
Decimal('3.000000000000000000000000000')
Meanwhile, math and cmath will silently convert their arguments to float and complex respectively, which could mean loss of precision.
decimal also has its own .sqrt(). See also calculating n-th roots using Python 3's decimal module
SymPy
Depending on your goal, it might be a good idea to delay the calculation of square roots for as long as possible. SymPy might help.
SymPy is a Python library for symbolic mathematics.
import sympy
sympy.sqrt(2)
# => sqrt(2)
This doesn't seem very useful at first.
But sympy can give more information than floats or Decimals:
sympy.sqrt(8) / sympy.sqrt(27)
# => 2*sqrt(6)/9
Also, no precision is lost. (√2)² is still an integer:
s = sympy.sqrt(2)
s**2
# => 2
type(s**2)
#=> <class 'sympy.core.numbers.Integer'>
In comparison, floats and Decimals would return a number which is very close to 2 but not equal to 2:
(2**0.5)**2
# => 2.0000000000000004
from decimal import Decimal
(Decimal('2')**Decimal('0.5'))**Decimal('2')
# => Decimal('1.999999999999999999999999999')
Sympy also understands more complex examples like the Gaussian integral:
from sympy import Symbol, integrate, pi, sqrt, exp, oo
x = Symbol('x')
integrate(exp(-x**2), (x, -oo, oo))
# => sqrt(pi)
integrate(exp(-x**2), (x, -oo, oo)) == sqrt(pi)
# => True
Finally, if a decimal representation is desired, it's possible to ask for more digits than will ever be needed:
sympy.N(sympy.sqrt(2), 1_000_000)
# => 1.4142135623730950488016...........2044193016904841204
NumPy
>>> import numpy as np
>>> np.sqrt(25)
5.0
>>> np.sqrt([2, 3, 4])
array([1.41421356, 1.73205081, 2. ])
docs
Negative
For negative reals, it'll return nan, so np.emath.sqrt() is available for that case.
>>> a = np.array([4, -1, np.inf])
>>> np.sqrt(a)
<stdin>:1: RuntimeWarning: invalid value encountered in sqrt
array([ 2., nan, inf])
>>> np.emath.sqrt(a)
array([ 2.+0.j, 0.+1.j, inf+0.j])
Another option, of course, is to convert to complex first:
>>> a = a.astype(complex)
>>> np.sqrt(a)
array([ 2.+0.j, 0.+1.j, inf+0.j])
Newton's method
Most simple and accurate way to compute square root is Newton's method.
You have a number which you want to compute its square root (num) and you have a guess of its square root (estimate). Estimate can be any number bigger than 0, but a number that makes sense shortens the recursive call depth significantly.
new_estimate = (estimate + num/estimate) / 2
This line computes a more accurate estimate with those 2 parameters. You can pass new_estimate value to the function and compute another new_estimate which is more accurate than the previous one or you can make a recursive function definition like this.
def newtons_method(num, estimate):
# Computing a new_estimate
new_estimate = (estimate + num/estimate) / 2
print(new_estimate)
# Base Case: Comparing our estimate with built-in functions value
if new_estimate == math.sqrt(num):
return True
else:
return newtons_method(num, new_estimate)
For example we need to find 30's square root. We know that the result is between 5 and 6.
newtons_method(30,5)
number is 30 and estimate is 5. The result from each recursive calls are:
5.5
5.477272727272727
5.4772255752546215
5.477225575051661
The last result is the most accurate computation of the square root of number. It is the same value as the built-in function math.sqrt().
This answer was originally posted by gunesevitan, but is now deleted.
Python's fractions module and its class, Fraction, implement arithmetic with rational numbers. The Fraction class doesn't implement a square root operation, because most square roots are irrational numbers. However, it can be used to approximate a square root with arbitrary accuracy, because a Fraction's numerator and denominator are arbitrary-precision integers.
The following method takes a positive number x and a number of iterations, and returns upper and lower bounds for the square root of x.
from fractions import Fraction
def sqrt(x, n):
x = x if isinstance(x, Fraction) else Fraction(x)
upper = x + 1
for i in range(0, n):
upper = (upper + x/upper) / 2
lower = x / upper
if lower > upper:
raise ValueError("Sanity check failed")
return (lower, upper)
See the reference below for details on this operation's implementation. It also shows how to implement other operations with upper and lower bounds (although there is apparently at least one error with the log operation there).
Daumas, M., Lester, D., Muñoz, C., "Verified Real Number Calculations: A Library for Interval Arithmetic", arXiv:0708.3721 [cs.MS], 2007.
Alternatively, using Python's math.isqrt, we can calculate a square root to arbitrary precision:
Square root of i within 1/2n of the correct value, where i is an integer:Fraction(math.isqrt(i * 2**(n*2)), 2**n).
Square root of i within 1/10n of the correct value, where i is an integer:Fraction(math.isqrt(i * 10**(n*2)), 10**n).
Square root of x within 1/2n of the correct value, where x is a multiple of 1/2n:Fraction(math.isqrt(x * 2**(n)), 2**n).
Square root of x within 1/10n of the correct value, where x is a multiple of 1/10n:Fraction(math.isqrt(x * 10**(n)), 10**n).
In the foregoing, i or x must be 0 or greater.
Binary search
Disclaimer: this is for a more specialised use-case. This method might not be practical in all circumstances.
Benefits:
can find integer values (i.e. which integer is the root?)
no need to convert to float, so better precision (can be done that well too)
I personally implemented this one for a crypto CTF challenge (RSA cube root attack),where I needed a precise integer value.
The general idea can be extended to any other root.
def int_squareroot(d: int) -> tuple[int, bool]:
"""Try calculating integer squareroot and return if it's exact"""
left, right = 1, (d+1)//2
while left<right-1:
x = (left+right)//2
if x**2 > d:
left, right = left, x
else:
left, right = x, right
return left, left**2==d
EDIT:
As #wjandrea have also pointed out, **this example code can NOT compute **. This is a side-effect of the fact that it does not convert anything into floats, so no precision is lost. If the root is an integer, you get that back. If it's not, you get the biggest number whose square is smaller than your number. I updated the code so that it also returns a bool indicating if the value is correct or not, and also fixed an issue causing it to loop infinitely (also pointed out by #wjandrea). This implementation of the general method still works kindof weird for smaller numbers, but above 10 I had no problems with.
Overcoming the issues and limits of this method/implementation:
For smaller numbers, you can just use all the other methods from other answers. They generally use floats, which might be a loss of precision, but for small integers that should mean no problem at all. All of those methods that use floats have the same (or nearly the same) limit from this.
If you still want to use this method and get float results, it should be trivial to convert this to use floats too. Note that that will reintroduce precision loss, this method's unique benefit over the others, and in that case you can also just use any of the other answers. I think the newton's method version converges a bit faster, but I'm not sure.
For larger numbers, where loss of precision with floats come into play, this method can give results closer to the actual answer (depending on how big is the input). If you want to work with non-integers in this range, you can use other types, for example fixed precision numbers in this method too.
Edit 2, on other answers:
Currently, and afaik, the only other answer that has similar or better precision for large numbers than this implementation is the one that suggest SymPy, by Eric Duminil. That version is also easier to use, and work for any kind of number, the only downside is that it requires SymPy. My implementation is free from any huge dependencies if that is what you are looking for.
Arbitrary precision square root
This variation uses string manipulations to convert a string which represents a decimal floating-point number to an int, calls math.isqrt to do the actual square root extraction, and then formats the result as a decimal string. math.isqrt rounds down, so all produced digits are correct.
The input string, num, must use plain float format: 'e' notation is not supported. The num string can be a plain integer, and leading zeroes are ignored.
The digits argument specifies the number of decimal places in the result string, i.e., the number of digits after the decimal point.
from math import isqrt
def str_sqrt(num, digits):
""" Arbitrary precision square root
num arg must be a string
Return a string with `digits` after
the decimal point
Written by PM 2Ring 2022.01.26
"""
int_part , _, frac_part = num.partition('.')
num = int_part + frac_part
# Determine the required precision
width = 2 * digits - len(frac_part)
# Truncate or pad with zeroes
num = num[:width] if width < 0 else num + '0' * width
s = str(isqrt(int(num)))
if digits:
# Pad, if necessary
s = '0' * (1 + digits - len(s)) + s
s = f"{s[:-digits]}.{s[-digits:]}"
return s
Test
print(str_sqrt("2.0", 30))
Output
1.414213562373095048801688724209
For small numbers of digits, it's faster to use decimal.Decimal.sqrt. Around 32 digits or so, str_sqrt is roughly the same speed as Decimal.sqrt. But at 128 digits, str_sqrt is 2.2× faster than Decimal.sqrt, at 512 digits, it's 4.3× faster, at 8192 digits, it's 7.4× faster.
Here's a live version running on the SageMathCell server.
find square-root of a number
while True:
num = int(input("Enter a number:\n>>"))
for i in range(2, num):
if num % i == 0:
if i*i == num:
print("Square root of", num, "==>", i)
break
else:
kd = (num**0.5) # (num**(1/2))
print("Square root of", num, "==>", kd)
OUTPUT:-
Enter a number: 24
Square root of 24 ==> 4.898979485566356
Enter a number: 36
Square root of 36 ==> 6
Enter a number: 49
Square root of 49 ==> 7
✔ Output 💡 CLICK BELOW & SEE ✔

Python float operations give complex result

eq = (((1 - (2 * normal_rpm - s8) ** s1) * s2 * math.sin(normal_rpm ** s3 / s4) * (1 - math.sin((normal_rpm + s5) ** (2) + 5) + s6) / (s7))) + 0.67
is my formula for this variable, where the S variables are floats. this sometimes returns a result like this
(0.6806708980989302+0.008606807113252896j)
I cannot use this result in further math, I need a float, even if I have to round the answer a bit.
This is not a rounding problem, but you are raising a negative number to a fractional exponent (e.g. you're taking the square root of -5).
For example:
In [2]: (-5)**0.5
Out[2]: (1.3691967456605067e-16+2.23606797749979j)
If you cannot accept complex numbers as result then the only other logical way out is to raise an error when this happens (there is no real number that multiplied by itself gives, or gets near, -5).
If this is not expected you should double-check the formula or formulas preceding it because may be there is a typo, or may be there are some preconditions you need to check before applying this formula.

What does pow(a, b, c) do when the exponent is negative?

Python allows a third argument in the built-in function pow that basically computes the exponentiation modulo this third argument (pow(a,b,c) = a**b % c).
How does it work when the exponent is negative? E.g.:
pow(6, -2, 13)
#-> 4
pow(6, -2, 12)
#-> Traceback (most recent call last):
#-> File "<stdin>", line 1, in <module>
#-> ValueError: base is not invertible for the given modulus
From the python built-in functions documentation:
For int operands base and exp, if mod is present, mod must also be of integer type and mod must be nonzero. If mod is present and exp is negative, base must be relatively prime to mod. In that case, pow(inv_base, -exp, mod) is returned, where inv_base is an inverse to base modulo mod.
which means that in your example, python calculates the inverse of 6 (so that 6 * inverse = 1) and calculates pow(inverse, 2, 13). In this case the inverse of 6 mod 13 is 11 (6 * 11 = 66 = 1 mod 13) and you calculate 11 ** 2 = 121 = 4 mod 13.
I think nobody answered your exact question. pow(6, -2, 13) is six to the minus second power modulo 13, that is, something (from range(13)) that gives 1 when multiplied with 6 squared. That is 4, because 4 * 6**2 == 144, which is 1 modulo 13.
The same thing modulo 12 doesn't exist, since whatever you multiply by 36 will be divisible by 12, so you'll always get 0 (and never 1) mod 12.
When the second argument is -1, it calculates the modular inverse of a (mod c). Using other negative powers -n will return the modular inverse to the n-th power (mod c).
https://en.wikipedia.org/wiki/Modular_multiplicative_inverse
Have you tried to check it out for yourself? Python used to not support negative exponents when the third argument was supplied, something they changed in version 3.8.x, and now what it does is allow you to compute the modular inverse (as opposed to the 'standard' inverse when dealing with the reals).
So, if example pow(2, -1, 3) would tell you the inverse in mod 3 which would be 2, because 2*2 =4 = 1 mod 3
pow(base, exp) = base**exp
pow(12,2) = 144 = 12**2
Now computation of modular inverses in supported 3.8 afterwards. Before that they denied to inverse to base modulu

Built in double-asterisk power function not working as expected [duplicate]

This question already has answers here:
Calculation error with pow operator
(4 answers)
Closed 5 years ago.
This prints -2.4:
print(-3**0.8)
But this prints an imaginary number...?
a = -3
b = 0.8
print(a**b)
I can't figure out what is causing this and this problem is breaking my program. How do you make it so that the second statement outputs the same as the first in a general case that works for positive and negative values for a?
Per the Python 3.6 documentation:
6.5. The power operator
The power operator binds more tightly than unary operators on its left; it binds less tightly than unary operators on its right. The syntax is:
power ::= ( await_expr | primary ) ["**" u_expr]
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.
Thus, in the first example:
>>> -3 ** 0.8
-2.4082246852806923
It's evaluated right to left as ** has higher precedence than unary -, binding tighter -- so here, 3 ** 0.8 is evaluated first, then the unary - operator is applied for a negative value. In the second example however, the expression is equivalent (-3) ** 0.8 as -3 is stored in a name, and evaluation results is an imaginary number:
>>> a = -3
>>> b = 0.8
>>> a ** b
(-1.9482946966653392+1.4155189542146738j)
A solution would be to calculate the result without unary operators, then applying a sign as necessary, per Shakar Bhattarai's answer:
>>> int(a / abs(a)) * (abs(a) ** b)
-2.4082246852806923
The first part, int(a / abs(a)) evaluates to either -1.0 or 1.0 depending on if a is negative or not, basically applying the sign. It then multiplies that by the result of a ** b regardless of a's sign. That will first compute a ** b disregarding it's sign, then applying the sign as necessary. This will get rid of the discrepancy. You could apply the same concept with math.copysign:
>>> math.copysign(1, a) * (abs(a) ** b)
-2.4082246852806923
This will just copy the sign from a to 1, which will give -1.0 or 1.0 based on negativity.
This is because of the precedence of the power operator. The power operator binds tighter than unary operators. So:
-3 ** 0.8
is evaluated as
-(3 * 0.8)
You can see how Python parses your code using the ast module:
>>> import ast
>>> ast.dump(ast.parse('-3 ** 0.8'))
'Module(body=[Expr(value=UnaryOp(op=USub(), operand=BinOp(left=Num(n=3), op=Pow(), right=Num(n=0.8))))])'
>>>
In the above, the 3 ** 0.8 is treated as one expression with ** being the operator. The unary minus is then applied to the value of the inner expression.
However, in your second example the values are stored in variables, so the precedence does not affect the expression. So a ** b is equivlent to (-3) ** 0.8
The solution is to bind the unary minus to the three using parenthesis:
>>> (-3) ** 0.8
(-1.94829469666534+1.4155189542146727j)
>>>
The ** operator has the highest precedence over all other operators. Hence when you use
print(-3**0.8)
python first evaluates the exponential and then negates it.
But when you run
a = -3
b = 0.8
print(a**b)
a has implicitly been negated first. Hence the result is effectively a imaginary number (a negative number raised to a fractional exponent)
To solve your issue, you could do something like
print (int(a/abs(a))*(abs(a)**b))

Calculation error with pow operator

What should print (-2 ** 2) return? According to my calculations it should be 4, but interpreter returns -4.
Is this Python's thing or my math is that terrible?
According to docs, ** has higher precedence than -, thus your code is equivalent to -(2 ** 2). To get the desired result you could put -2 into parentheses
>>> (-2) ** 2
4
or use built-in pow function
>>> pow(-2, 2)
4
or math.pow function (returning float value)
>>> import math
>>> math.pow(-2, 2)
4.0
The ** operation is done before the minus. To get the results expected, you should do
print ((-2) ** 2)
From the documentation:
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.
A full detail of operators precedence is also available in the documentation. You can see the last line is (expr) which force the expr to be evaluated before being used, hence the result of (-2) ** 2 = 4
you can also use math library...
math.pow(-2,2) --> 4
-math.pow(2,2) --> -4
math.pow(4,0.5) --> 2
Python has a problem and does not see the -2 as a number. This seems to be by design as it is mentioned in the docs.
-2 is interpreted as -(2) {unary minus to positive number 2}
That usually doesn't give a problem but in -a ** 2 the ** has higher priority as - and so with - interpreted as a unary operatoe instead of part of the number -2 ** 2 evaluates to -2 instead of 2.

Categories