Handling exception - negative square root in python - python

I am trying to write a piece of code to handle the exception of negative square roots, since I only want a positive result. My code is:
def sqRoot(x):
try:
result = (x)**0.5
except ValueError:
result = "This is a negative root"
except TypeError:
result = "Please enter a number"
return result
For some reason, when I run this code using the call
x = sqRoot(-200)
I don't get the error, but instead python is giving me the result as a complex number. I can't seem to see the error in my code.

Shifting this discussion from the comments...
In Python 3.0 the behaviour of the power operator changed. In earlier versions of python, raising a negative number to a fractional power raised a ValueError exception, but in Python 3 it yields a complex result.
An alternative for finding the square root is the python is the math.sqrt function. In Python 3 this raises a ValueError exception when used with a negative number:
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> math.sqrt(-200)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: math domain error

If python 3 returns a complex number and that is not what you want, you can always achieve the desired output with an if statement:
def sqRoot(x):
if not isinstance(x, (int, long, float)):
return "Please enter a number"
if x < 0:
return "This is a negative root"
return (x)**0.5

Since in python 3, the square root of a negative number is defined (as complex), you will have to test for it yourself:
def sqRoot(x):
if not type(x) in [int, long, float]:
result = "Please enter a number"
elif x < 0:
result = "This is a negative root"
else:
result = (x)**0.5
return result
By the way, I don't think that it's good programming practice to have the function return numbers in one case, and strings in the other. I think that is better done by raising errors.

Related

python self calling unit test function not raising an error

I have a background in C and Fortran programming, however I have been trying to learn Python and object orientation. To help with some of my projects I have been trying to define some additional unit tests.
I have used the AssertAlmostEqual unit test, but I found that for large numbers it doesn't work so well, as it works to 7 decimal places (I think). When testing large exponents this becomes a bit useless. So I tried to define an assertEqualSigFig test for significant figures in stead of decimal places. This test was inspired by a stack over flow post, however I cannot find the original post I'm afraid.
This test works for integers floats and booleans however I wanted to see if it would also work with complex numbers. By splitting the numbers into the real and imaginary components and then calling itself. When this happens, no assertion Error is raised and I'm not sure why.
Here is my code:
import unittest
import math
class MyTestClass(unittest.TestCase):
"""
MyTestClass
Adds additional tests to the unit test module:
defines:
- AssertEqualSigFig
description:
- Used in place of the assertAlmostEqualTest, this tests two values
are the same to 7 significant figures (instead of decimal places)
args:
- any two integers, booleans, floats or complex number
returns:
- assertion error if not equal to defined significant figures
"""
def AssertEqualSigFig(self, expected, actual, sig_fig = 7):
if sig_fig < 1:
msg = "sig fig must be more than 1"
raise ValueError(msg)
try:
if isinstance(expected, bool):
if expected != actual:
raise AssertionError
else:
return
elif isinstance(expected, (int,float)):
pow_ex = int(math.floor(math.log(expected,10)))
pow_ac = int(math.floor(math.log(actual,10)))
tolerance = pow_ex - sig_fig + 1
tolerance = (10** tolerance)/2.0
if abs(expected - actual) > tolerance:
raise AssertionError
else:
return
elif isinstance(expected, complex):
#this part doesnt raise an error when it should
a_real = actual.real
a_imag = actual.imag
e_real = expected.real
e_imag = expected.imag
self.AssertEqualSigFig(self, a_imag, e_imag)
self.AssertEqualSigFig(self, a_real, e_real)
except AssertionError:
msg = "{0} ! = {1} to {2} sig fig".format(expected, actual, sig_fig)
raise AssertionError(msg)
This test fails when complex numbers are involved. Here are the unit tests of the unit test that it fails:
import unittest
from MyTestClass import MyTestClass
class TestMyTestClass(MyTestClass):
def test_comlex_imag_NE(self):
a = complex(10,123455)
b = complex(10,123333)
self.assertRaises(AssertionError, self.AssertEqualSigFig, a, b)
def test_complex_real_NE(self):
a = complex(2222222,10)
b = complex(1111111,10)
self.assertRaises(AssertionError, self.AssertEqualSigFig, a, b)
if __name__ == "__main__":
unittest.main()
I think it is because the self.AssertEqualSigFig call does not raise an error. I'm sure there is a silly thing I have missed, But I am still learning. Can anybody help?
I was being an idiot, I have found the solution
I should have been using
MyTestClass.assertEqualSigFig
and not
self.assertEqualSigFig

Is there any way to make Python .format() thow an exception if the data won't fit the field?

I want to normalize floating-point numbers to nn.nn strings, and to do some special handling if the number is out of range.
try:
norm = '{:5.2f}'.format(f)
except ValueError:
norm = 'BadData' # actually a bit more complex than this
except it doesn't work: .format silently overflows the 5-character width. Obviously I could length-check norm and raise my own ValueError, but have I missed any way to force format (or the older % formatting) to raise an exception on field-width overflow?
You can not achieve this with format(). You have to create your custom formatter which raises the exception. For example:
def format_float(num, max_int=5, decimal=2):
if len(str(num).split('.')[0])>max_int:
raise ValueError('Integer part of float can have maximum {} digits'.format(max_int))
return "{:.2f}".format(num)
Sample run:
>>> format_float(123.456)
'123.46'
>>> format_float(123.4)
'123.40'
>>> format_float(123789.456) # Error since integer part is having length more than 5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in format_float
ValueError: Integer part of float can have maximum 5 digits

How to calculate Python float-number-th root of float number

I found the following answer here on Stackoverflow:
https://stackoverflow.com/a/356187/1829329
But it only works for integers as n in nth root:
import gmpy2 as gmpy
result = gmpy.root((1/0.213), 31.5).real
print('result:', result)
results in:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-eb4628226deb> in <module>()
8
----> 9 result = gmpy.root((1/0.213), 31.5).real
10
11 print('result:', result)
TypeError: root() requires 'mpfr','int' arguments
What is a good and precise way to calculate such a root?
(This is the python code representation of some formular, which I need to use to calculate in a lecture.)
EDIT#1
Here is my solution based on Spektre's answer and information from the people over here at http://math.stackexchange.com.
import numpy as np
def naive_root(nth, a, datatype=np.float128):
"""This function can only calculate the nth root, if the operand a is positive."""
logarithm = np.log2(a, dtype=datatype)
exponent = np.multiply(np.divide(1, nth, dtype=datatype), logarithm, dtype=datatype)
result = np.exp2(exponent, dtype=datatype)
return result
def nth_root(nth, a, datatype=np.float128):
if a == 0:
print('operand is zero')
return 0
elif a > 0:
print('a > 0')
return naive_root(nth, a, datatype=datatype)
elif a < 0:
if a % 2 == 1:
print('a is odd')
return -naive_root(nth, np.abs(a))
else:
print('a is even')
return naive_root(nth, np.abs(a))
see Power by squaring for negative exponents
anyway as I do not code in python or gmpy here some definitions first:
pow(x,y) means x powered by y
root(x,y) means x-th root of y
As these are inverse functions we can rewrite:
pow(root(x,y),x)=y
You can use this to check for correctness. As the functions are inverse you can write also this:
pow(x,1/y)=root(y,x)
root(1/x,y)=pow(y,x)
So if you got fractional (rational) root or power you can compute it as integer counterpart with inverse function.
Also if you got for example something like root(2/3,5) then you need to separate to integer operands first:
root(2/3,5)=pow(root(2,5),3)
~11.18034 = ~2.236068 ^3
~11.18034 = ~11.18034
For irational roots and powers you can not obtain precise result. Instead you round the root or power to nearest possible representation you can to minimize the error or use pow(x,y) = exp2(y*log2(x)) approach. If you use any floating point or fixed point decimal numbers then you can forget about precise results and go for pow(x,y) = exp2(y*log2(x)) from the start ...
[Notes]
I assumed only positive operand ... if you got negative number powered or rooted then you need to handle the sign for integer roots and powers (odd/even). For irational roots and powers have the sign no meaning (or at least we do not understand any yet).
If you are willing to use Python 3.x, the native pow() will do exactly what you want by just using root(x,y) = pow(x,1/y). It will automatically return a complex result if that is appropriate.
Python 3.4.3 (default, Sep 27 2015, 20:37:11)
[GCC 5.2.1 20150922] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> pow(1/0.213, 1/31.5)
1.0503191465568489
>>> pow(1/0.213, -1/31.5)
0.952091565004975
>>> pow(-1/0.213, -1/31.5)
(0.9473604081457588-0.09479770688958634j)
>>> pow(-1/0.213, 1/31.5)
(1.045099874779588+0.10457801566102139j)
>>>
Returning a complex result instead of raising a ValueError is one of changes in Python 3. If you want the same behavior with Python 2, you can use gmpy2 and enable complex results.
>>> import gmpy2
>>> gmpy2.version()
'2.0.5'
>>> gmpy2.get_context().allow_complex=True
>>> pow(1/gmpy2.mpfr("0.213"), 1/gmpy2.mpfr("31.5"))
mpfr('1.0503191465568489')
>>> pow(-1/gmpy2.mpfr("0.213"), 1/gmpy2.mpfr("31.5"))
mpc('1.0450998747795881+0.1045780156610214j')
>>> pow(-1/gmpy2.mpfr("0.213"), -1/gmpy2.mpfr("31.5"))
mpc('0.94736040814575884-0.094797706889586358j')
>>> pow(1/gmpy2.mpfr("0.213"), -1/gmpy2.mpfr("31.5"))
mpfr('0.95209156500497505')
>>>
Here is something I use that seems to work with any number just fine:
root = number**(1/nthroot)
print(root)
It works with any number data type.

Python indentation mystery

Why am I getting the following error? The last print statement should not be a part of the while loop.
>>> while n>= 0:
... n = n-1
... print(n)
... print ("TO A!!")
File "<stdin>", line 4
print ("TO A!!")
^
SyntaxError: invalid syntax
You need to press enter after your while loop to exit from the loop
>>> n = 3
>>> while n>=0:
... n = n-1
... print (n)
... # Press enter here
2
1
0
-1
>>> print ("To A!!")
To A!!
Note:- ... implies that you are still in the while block
The default python shell works OK for typing but it really does not understand pasting from clipboard. The real solution is to install ipython, which is an advanced shell for python with many niceties:
% ipython3
Python 3.4.2 (default, Oct 8 2014, 13:08:17)
Type "copyright", "credits" or "license" for more information.
IPython 2.3.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: n = 5
In [2]: while n >= 0:
...: n = n-1
...: print(n)
...: print ("TO A!!")
...:
4
3
2
1
0
-1
TO A!!
In [3]:
I guess that the error shows up because python shell don't support that. It want you to do one thing in a time.! I do the same things in my python 2.7 shell and it said:
File "<pyshell#4>", line 4
print 'to all'
^
IndentationError: unindent does not match any outer indentation level
when I do the same thing in my python 3.4 shell, it said: unexpected indent.

Unorderable Types Error when working in SublimeREPL

I seem to be having a problem using sublimeREPL to run python code with user input in sublime text 2. I have a working piece of code that I can use in the command prompt that will not execute inside REPL. The error seems to be that REPL cannot handle the format of the input and assumes it is a string. My python is fairly limited so is there a way to make the REPL play nice with my code or do I need to specify the input?
Note: Casting tempInput as a int each time will work but is tedious.
The Code:
# Matthew P
# A program to calculate average grades
def avg(total, elements):
return total / elements
tempInput = 0
runningTot = 0
numGrades = 0
print("\nEnter Grades (Negative Value to Escape): ")
while tempInput > -1:
tempInput = input("-->")
if tempInput > -1:
runningTot = runningTot + tempInput
numGrades = numGrades + 1
print("\nQuit Command Givem")
print("Average Grade: " + str(avg(runningTot,numGrades)))
print("Grade Sum: " + str(runningTot))
print("Number of Grades" + str(numGrades))
The Output from command prompt:
~\Documents\Python Scripts>userinput.py
Enter Grades (Negative Value to Escape):
-->99
-->98
-->97
-->96
-->95
-->-1
Quit Command Givem
Average Grade: 97
Grade Sum: 485
Number of Grades 5
and the error when running in sublimeREPL (I ran is using the ctrl+,,f command)
Python 3.3.3 (v3.3.3:c3896275c0f6, Nov 18 2013, 21:18:40) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Enter Grades (Negative Value to Escape):
-->100
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 17, in <module>
TypeError: unorderable types: str() > int()
>>>
input() returns a string, but you are comparing it against an integer:
tempInput = input("-->")
if tempInput > -1:
Use int() to make the comparison:
tempInput = int(input("-->"))
You ran the code on the command line with Python 2, where input() evaluates the entered string as a Python expression. Python 2 also doesn't mind you comparing numbers and strings; numbers always sort before numbers.
In Sublime, you ran the code under Python 3, however, where input() only takes string input.

Categories