5

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?

Jack Buckley
  • 161
  • 6
  • 2
    See https://wiki.haskell.org/Power_function – chepner Sep 17 '17 at 17:57
  • Both Haskell and Python return the first complex root of `-1` (~0.5-0.866i) -- I guess most programming languages do that as well, provided one uses a suitable complex type. When using doubles, NaN arises since the result is not real. – chi Sep 17 '17 at 19:55

3 Answers3

5

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
>
K. A. Buhr
  • 45,621
  • 3
  • 45
  • 71
1

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

Istvan
  • 216
  • 1
  • 7
1

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 ;)

Bernardo Duarte
  • 4,074
  • 4
  • 19
  • 34