Quite recently I’ve encountered a weird issue. I tried to calculate a **cubic root** from a **negative number** in **Python**:

But it’s kind of *obvious* that . So why is this error?

Next thing I tried to the same in **JavaScript** (it’s easy to find a console in browser…):

It seems that it worked the same, clearly the issue was in the underlying implementation. But first quick glance on the workaround solution:

## Workaround solution

I needed to calculate that **cubic root** and I knew that there has to be *at least one real solution*, so I used this workaround:

That’s because it’s for **negative** numbers.

Note that there are usually roots of **cubic root**: two *complex* ones and one *real*.

## Reason of issues with cubic root

I was wondering about the reason behind that behaviour. To find out I decided to check the documentation
of **Python** and source code of **Python** implementation and see where it can lead me next.

### Power function in Python documentation and source code

In python doc it’s clearly written:

```
If both x and y are finite, `x` is negative, and `y` is not an integer then `pow(x, y)` is undefined, and raises `ValueError`.
```

The source code of **cpython** only confirmed that mathmodule.c.h
behaviour. But there is no explicit reason why mentioned. It’s also written:

```
Exceptional cases follow Annex ‘F’ of the C99 standard as far as possible.
```

It seemed that **C99** standard is a good lead for next steps.

### Annex F of the C99 standard

Here is a link to the standard: C99 standard In F.9.4.4 it’s clearly written:

```
pow(x, y) returns a NaN and raises the ‘‘invalid’’ floating-point exception for
finite x < 0 and finite non-integer y.
```

So it seems that when designing **floating-point arithmetic** they just made a decision to raise exception when it’s
not obvious when the result of **power** function will be *complex* or not. I think it might be good decision - the
**C99 standard** is already quite complicated and adding more corner cases there could create a nightmare for
people who wants to implement **math** functions using that standard. And finding a workaround is really easy in
cases when this is obvious that **real** roots exist.

This is also complaint with IEEE Standard 754.

### What about pow in C++?

From **C++** reference math pow:

```
If base is finite and negative and exp is finite and non-integer, a domain
error occurs and a range error may occur.
(...)
If the implementation supports IEEE floating-point arithmetic (IEC 60559)
```

Actually in **C++11** and later ones there is a special function for
cubic roots cbrt, which can handle
the **negative** argument, but they didn’t decide to use that one in **cpython**
implementation of **power** function.

## Leave a Comment