# Why \`inv(Complex(0.0, 0.0))\` returns \`Complex(NaN, NaN)\`?

**URL:** <https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694>\
**Category:** Internals & Design\
**Tags:** complex-numbers\
**Created:** [January 9, 2023, 5:42am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694 "2023-01-09T05:42:23Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![hyrodium](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hyrodium/32/27015_2.png) [@hyrodium](https://discourse.julialang.org/u/hyrodium)\
**Post date:** [January 9, 2023, 5:42am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/1 "2023-01-09T05:42:23Z")

</div>

In Julia, `inv(Complex(0.0, 0.0))` is evaluated as

```julia
julia> c = inv(Complex(0.0, 0.0))
NaN + NaN*im

julia> isnan(c)
true

julia> isinf(c)
false

julia> versioninfo()
Julia Version 1.8.4
Commit 00177ebc4fc (2022-12-23 21:32 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 16 × AMD Ryzen 7 2700X Eight-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, znver1)
  Threads: 1 on 16 virtual cores

```

But I think it should be

```julia
julia> c = inv(Complex(0.0, 0.0))
Inf - Inf*im

julia> isnan(c)
false

julia> isinf(c)
true

```

Because

\begin{aligned} \frac{1}{a+bi} &= \frac{a}{a^2+b^2} + i \frac{-b}{a^2+b^2} \\ \lim\_{a \to +0\\b \to +0}\frac{a}{a^2+b^2} &= +\infty \\ \lim\_{a \to +0\\b \to +0}\frac{-b}{a^2+b^2} &= -\infty \end{aligned}

Is there any reason for the `NaN` value? If so, it would be nice to have more documentation about this.

---

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [January 9, 2023, 7:53am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/2 "2023-01-09T07:53:20Z")

</div>

Hello!

Your expressions are the result of evaluating limits. However, even your limits are not well defined, since both `a` and `b` could be approximated from the other side (negative), being both real numbers.

In computing, to deal with these situations in an uniform way, the [IEEE 754 standard](https://en.wikipedia.org/wiki/IEEE_754) defines the inverse of 0.0 as `NaN` (not-a-number).

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 9, 2023, 8:18am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/3 "2023-01-09T08:18:30Z")

</div>

> [@nandoconde](#):
>
> the inverse of 0.0 as `NaN` (not-a-number).

```julia
julia> inv(0.0)
Inf

julia> 1/0.0
Inf

```

Do you mean that the standard defines it for complex zeros?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 9, 2023, 8:25am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/4 "2023-01-09T08:25:04Z")

</div>

If you look at

\frac{a}{a^2+b^2}

If you let b go to zero first, then a, the limit is \infty. But if you let a go to zero first, then the expression is always zero (0/b). So the limit isn’t well defined, but for a different reason.

As for whether one approaches the limit from positive or negative, you have this:

```julia
julia> inv(0.0)
Inf

julia> inv(-0.0)
-Inf

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [January 9, 2023, 8:25am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/5 "2023-01-09T08:25:44Z")

</div>

> [@nandoconde](#):
>
> In computing, to deal with these situations in an uniform way, the [IEEE 754 standard](https://en.wikipedia.org/wiki/IEEE_754) defines the inverse of 0.0 as `NaN` (not-a-number).

That is not correct. The multiplicative inverse of 0.0 with IEEE\_754 is Inf.

```julia
julia> inv(0.0)
Inf

julia> inv(-0.0)
-Inf

julia> 0.0 / 0.0
NaN

```

> [@nandoconde](#):
>
> However, even your limits are not well defined, since both `a` and `b` could be approximated from the other side (negative), being both real numbers.

There are more than two sides here in the complex plane. In the figure below, x is the real component, y is the imaginary component, and z is the angle of the complex number.

```julia
julia> using Makie, CairoMakie

julia> begin
           fig = Figure();
           ax3d = Axis3(fig[1, 1]; aspect = (1, 1, 1),
                  perspectiveness = 0.5, azimuth = 2.19, elevation = 0.9)
           x = -1:0.1:1
           y = -1:0.1:1
           z = angle.(1 ./ (x .+ y'*im))
           p = surface!(x, y, z)
           ax3d.xlabel = "Real"
           ax3d.ylabel = "Imag"
           ax3d.zlabel = "Angle of Multiplicative Inverse"
           save("multiplicative_inverse.png", fig)
       end

```

 ![multiplicative_inverse](https://global.discourse-cdn.com/julialang/original/3X/e/b/eb3fb88ba3abaf649a0ec3f670206ccb78ad76fe.png)

I think the limit argument is not very convincing here.

---

<div class="post-metadata">

**Author:** ![hyrodium](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hyrodium/32/27015_2.png) [@hyrodium](https://discourse.julialang.org/u/hyrodium)\
**Post date:** [January 9, 2023, 9:12am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/6 "2023-01-09T09:12:22Z")

</div>

> If you let b go to zero first, then a, the limit is ∞ . But if you let a go to zero first, then the expression is always zero ( 0/b ).

Ahh, sorry I was stupid.

What I was trying to say is, it is better to define `inv` function that is commutative with `abs` function.

```julia
julia> c1 = Complex(3,4)
3 + 4im

julia> inv(abs(c1))
0.2

julia> abs(inv(c1))
0.2

julia> c2 = Complex(0,0)
0 + 0im

julia> inv(abs(c2))
Inf

julia> abs(inv(c2)) # This should be Inf
NaN

```

In the theory of complex functions, we sometimes equate all infinite points as \infty = 1/0 (See [Riemannian sphere](https://en.wikipedia.org/wiki/Riemann_sphere)), so returning `NaN` is not useful here.

The choice for the return value of `inv(Complex(0.0, 0.0))` will be the following:

- `Complex(NaN, NaN)`
  - The current output.
  - As @mkitti mentioned, the limit of arguments does not exist. So returning `NaN` makes a little sense (similar to `0.0 / 0.0`).

- `Complex(Inf, 0.0)` or `Complex(0.0, Inf)`
  - If we need `inv∘abs == abs∘inv` (or `≈` ), these will be acceptable.
  - But choosing the position of `0.0` is not straightforward, so this is not a good way.

- `Complex(Inf, Inf)`
  - This is okay.

- `Complex(Inf, -Inf)`
  - This is better because this is consistent with `inv(Complex(Inf,Inf))`.

```julia
julia> inv(Complex(Inf,Inf))
0.0 - 0.0im

julia> inv(Complex(-Inf,Inf))
-0.0 - 0.0im

julia> inv(Complex(Inf,-Inf))
0.0 + 0.0im

julia> inv(Complex(-Inf,-Inf))
-0.0 + 0.0im

julia> (inv∘inv)(Complex(Inf,Inf)) # I also hope `inv∘inv ≈ id`
NaN + NaN*im

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [January 9, 2023, 9:31am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/7 "2023-01-09T09:31:56Z")

</div>

> <https://github.com/JuliaLang/julia/issues/5234>
>
> (Context: this issue has come up recently in #4967 and elsewhere)
> 
> We currently …don't treat the results of indeterminate computations consistently between real and complex arithmetic.
> \## Example 1: cosine
> 
> \`\`\` julia
> julia\> cos(Inf)
> ERROR: DomainError
> in cos at math.jl:277
> 
> julia\> cos(complex(Inf,0))
> NaN - 0.0im
> \`\`\`
> \## Example 2: inverse
> \### inverse of 0
> 
> \`\`\` julia
> julia\> inv(0.0)
> Inf
> 
> julia\> inv(complex(0.0, 0.0))
> NaN + NaN\*im
> \`\`\`
> 
> This illustrates a problem with infinity and signed zero. Unlike real infinities, of which there are only two \`FloatingPoint\` values, you can have 13 possible representations of complex infinities which convey different information about the phase (argument) of the complex infinity:
> 
> \`\`\` julia
> complex(+Inf, +0.0) #phase is exactly 0 or approaches 0 from the first quadrant
> complex(+Inf, +Inf) #phase is in (0, pi/2), i.e. the first quadrant excluding the edges
> complex(+0.0, +Inf) #phase is exactly pi/2 or approaches pi/2 from the first quadrant
> complex(-0.0, +Inf) #phase approaches pi/2 from the second quadrant
> complex(-Inf, +Inf) #phase is in (pi/2, pi), i.e. the second quadrant excluding the edges
> complex(-Inf, +0.0) #phase is exactly pi or approaches pi from the second quadrant
> complex(-Inf, -0.0) #phase approaches pi from the third quadrant
> complex(-Inf, -Inf) #phase is in (pi, 3pi/2), i.e. the third quadrant excluding the edges
> complex(-0.0, -Inf) #phase approaches 3pi/2 from the third quadrant
> complex(+0.0, -Inf) #phase is exactly 3pi/2 or approaches 3pi/2 from the fourth quadrant
> complex(+Inf, -Inf) #phase is in (3pi/2, 2pi), i.e. the fourth quadrant excluding the edges
> complex(+Inf, -0.0) #phase approaches 2pi from the fourth quadrant
> complex(NaN, NaN) #phase cannot be determined to lie in exactly one of the above regions
> \# and hence the infinity has no valid non-NaN representation in floating point
> \`\`\`
> 
> The result is correct \_if\_ we work with unsigned zeros. However, after accounting for the signed zeros in \`complex(+0.0, +0.0)\`, this result should be \`complex(+Inf, +Inf)\`. A \`DivideError\` might also be a reasonable alternative here.
> \### inverse of infinities
> 
> The inverse mapping is also problematic:
> 
> \`\`\` julia
> julia\> inv(Inf)
> 0.0
> 
> julia\> inv(complex(Inf,0))
> 0.0 - 0.0im
> 
> julia\> inv(complex(Inf,Inf))
> NaN + NaN\*im
> \`\`\`
> \### inverse of indeterminates
> 
> \`\`\` julia
> julia\> inv(NaN)
> NaN
> 
> julia\> inv(complex(0,NaN))
> NaN + NaN\*im
> 
> julia\> inv(complex(NaN, 0))
> NaN + NaN\*im
> 
> julia\> inv(complex(NaN, NaN))
> NaN + NaN\*im
> \`\`\`
> 
> Is it meaningful to distinguish between these three possible complex NaNs? It seems silly in this example, but consider also:
> 
> \`\`\` julia
> julia\> complex(0, NaN) + complex(0, NaN)
> complex(0.0,NaN)
> 
> julia\> complex(0, NaN) \* complex(0, NaN)
> NaN + NaN\*im
> \`\`\`
> 
> etc.
> \## Example 3: roots (nonintegral powers)
> 
> \`\`\` julia
> julia\> sqrt(-1)
> ERROR: DomainError
> 
> julia\> sqrt(complex(-1))
> 0.0 + 1.0im
> 
> julia\> (-1)^(-1/2)
> NaN
> 
> julia\> complex(-1)^(-1/2)
> 6.123233995736766e-17 - 1.0im
> \`\`\`
> 
> Whereas \`sqrt(-1)\` returns the notorious \`DomainError\`, the inverse square root (as computed by \`x-\>x^-1/2\` does not, but returns a \`NaN\` instead. This use of \`NaN\` is sanctioned by IEEE 754 in the specific case of a real operation with no real output.
> 
> \*\*tl;dr: if a floating-point computation returns an indeterminate value, when should it return a \`NaN\` (or any of its complex variants), and when should it throw an error like \`DivideError\` or \`DomainError\`?\*\* By my reading of IEEE 754, both of these behaviors are allowed (throwing an error would correspond to a signaling \`NaN\` which is trapped by the error handler). Each of these examples in isolation show valid behavior; however, we should be consistent.

---

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [January 9, 2023, 9:38am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/8 "2023-01-09T09:38:21Z")

</div>

> [@mkitti](#):
>
> That is not correct. The multiplicative inverse of 0.0 with IEEE\_754 is Inf.

OMG, true. Sorry, 7 AM…

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [January 9, 2023, 4:02pm UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/9 "2023-01-09T16:02:57Z")

</div>

My sense is that we are somewhat limited by our Cartesian description of complex values. If we moved to polar description, I think we might have a few more options. That is if we described the complex values in terms of `abs` and `angle` such that

```julia
θ = angle(C)
R = abs(C)
C = exp(θ*1im)

```

Then we could have `R == ∞` for some `θ` dependent on the original angle.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 9, 2023, 4:12pm UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/10 "2023-01-09T16:12:15Z")

</div>

> [@hyrodium](#):
>
> In Julia, `inv(Complex(0.0, 0.0))` is evaluated as
> 
> ```julia
> julia> c = inv(Complex(0.0, 0.0))
> NaN + NaN*im
> 
> ```

There was a detailed discussion of this topic, including a comparison with several languages/compilers and the [ISO standard](https://www.iso.org/standard/37994.html) in: [https://github.com/JuliaLang/julia/issues/22983](https://github.com/JuliaLang/julia/issues/22983)

TLDR: Julia’s behavior seems to be consistent with the ISO standard, and with the viewpoint that `0.0 + 0.0im` represents a limit of x + iy as x,y \to 0^+ but in which the order of the limits is undefined (hence giving `NaN` from division in which the resultt cannot be determined). It’s also consistent with `gfortran`, but other languages make different choices.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [January 10, 2023, 3:19am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/11 "2023-01-10T03:19:41Z")

</div>

Now that we’ve established that this already has been investigated and that we should not change this, perhaps we could discuss how to make a custom `Complex` type with the desired behavior?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 10, 2023, 3:41am UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/12 "2023-01-10T03:41:49Z")

</div>

Probably a lot easier just to define your own division operator `/′`, or check for zero denominators on a case-by-case basis since the desired behavior is probably application-dependent. Depends on what your practical use-case (if any) is.

---

<div class="post-metadata">

**Author:** ![hyrodium](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hyrodium/32/27015_2.png) [@hyrodium](https://discourse.julialang.org/u/hyrodium)\
**Post date:** [January 10, 2023, 4:15pm UTC](https://discourse.julialang.org/t/why-inv-complex-0-0-0-0-returns-complex-nan-nan/92694/13 "2023-01-10T16:15:39Z")

</div>

Thank you all for the conversation!  
I made a package [RiemannSphereOperations.jl](https://github.com/hyrodium/RiemannSphereOperations.jl) for complex number operations on the Riemann sphere.

```julia
julia> using RiemannSphereOperations

julia> inv′(complex(0,0))
Inf - Inf*im

julia> inv′(complex(0//1, 0//1))
1//0 - 1//0*im

julia> complex(Inf,-Inf) ==′ complex(-Inf,0)
true

julia> complex(Inf,-Inf) ==′ complex(1,0)
false

```
