Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find the cube root of a negative integer such that it does not return NaN?

Tags:

haskell

In Haskell, I have tried to find the cube root of a negative integer, for example, -1, without success.

I have used (-1) ** (1/3), but this returns a NaN. I thought that this might have something to do with type of the (1/3) fraction, but using (1/3 :: Double) yielded no success either.

As a result, my question is how can one find the cube root of -1 using Haskell so that it doesn't return NaN?

like image 784
Jack Buckley Avatar asked Sep 17 '17 14:09

Jack Buckley


3 Answers

For real numbers, the Haskell operator (**) is only defined for negative base (left-hand side) values when the exponent (right-hand side) is integer-valued. If this strikes you as strange, note that the C function pow behaves the same way:

printf("%f\n", pow(-1.0, 1.0/3.0));   // prints "-nan", for me

and so does Python's ** operator:

print((-1.0)**(1.0/3.0)) 
# gives: ValueError: negative number cannot be raised to fractional power

The problem is partially a mathematical one. The "correct answer" for raising a negative base to a non-integral power is far from obvious. See, for example, this question on the Mathematics SO.

If you only need a cube root that can handle negative numbers, the other answers given should work fine, except that @Istvan's answer should use signum instead of sign, like this:

cbrt x = signum x * abs x ** (1/3)

If you want a more general integral root function for real numbers, be warned that for even n, there are no nth roots of negative numbers that are real, so this is about the best you can do:

-- | Calculate nth root of b
root :: (Integral n, RealFloat b) => n -> b -> b
root n b | odd n && b < 0  = - abs b ** overn
         | otherwise       = b ** overn
    where overn = 1 / fromIntegral n

This gives:

> root 3 (-8)
-2.0
> root 4 (-8)
NaN      -- correct, as no real root exists
>
like image 155
K. A. Buhr Avatar answered Oct 27 '22 00:10

K. A. Buhr


I don't know Haskell, but you can do something like this: sign(x) * abs(x) ** (1/3)

like image 30
Istvan Avatar answered Oct 27 '22 00:10

Istvan


On ghci I've done something that seems to solve your problem:

let cbrt x = if x < 0 then -((-x) ** (1/3)) else x ** (1/3)

A simple cuberoot function.

As I'm still learning I don't know if this is a proper solution, so please let me know if there's something missing or wrong ;)

like image 43
Bernardo Duarte Avatar answered Oct 27 '22 00:10

Bernardo Duarte