It's easy to check if a number has a complex square root, that's the case if you have a negative number:
def has_complex_sqrt(num):
return num < 0
However it's harder to find out if a number has an irrational square root. There's a way that works if your number is a string because fractions.Fraction
can then calculate the exact represention for this number.
Then one uses the fact that the square root of a number can only be rational if each prime factor of the numerator and denumerator of the fraction representing the number has an even exponent. (There is a lot of ressources on the web backing this up)
So the steps to solve this are:
- get the exact fractional representation
- find the prime-factors
- and then check if each of them has an even exponent.
Implementing this in code:
from fractions import Fraction
def get_fraction_from_string(num):
return Fraction(num)
def get_prime_factors(n):
# Taken from http://stackoverflow.com/a/22808285/5393381
# you might implement another algorithm here!
i = 2
factors = []
while i * i <= n:
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors
from collections import Counter
def has_even_exponents(primefactorized):
return all(num % 2 == 0 for num in Counter(primefactorized).values())
And finally putting this all into one "super-function":
def has_irrational_sqrt(astring):
fract = get_fraction_from_string(astring)
primefactors_numerator = get_prime_factors(fract.numerator)
if not has_even_exponents(primefactors_numerator):
return True
primefactors_denominator = get_prime_factors(fract.denominator)
if not has_even_exponents(primefactors_denominator):
return True
return False
and for convenience another function that checks if any of both is True
:
def has_irrational_or_complex_sqrt(num):
return has_complex_sqrt(float(num)) or has_irrational_sqrt(num)
And now the interactive test:
>>> has_irrational_or_complex_sqrt('20')
True
>>> has_irrational_or_complex_sqrt('25')
False
>>> has_irrational_or_complex_sqrt('-1')
True
>>> has_irrational_or_complex_sqrt('-20')
True
>>> has_irrational_or_complex_sqrt('6.25')
False
That produces the expected values. Hurray!
If your input is already a float
this approach might not work!
>>> has_irrational_or_complex_sqrt('0.01')
False
>>> has_irrational_or_complex_sqrt(0.01) # Oups!
True
But in your example it works because 6.25
can be represented exactly as float:
>>> has_irrational_or_complex_sqrt(6.25)
False