# Multiplication with Complex numbers and Inf give inconsistent answers - bug?

#1

Dear All,

I expected that this

``````julia> 1*(im*Inf)
0.0 + Inf*im
``````

would give the same answer as this

``````julia> 1*im*Inf
NaN + Inf*im
``````

but it didn’t! Is this a bug?

My version:

``````julia> versioninfo()
Julia Version 0.6.3-pre.1
Commit 41143e875d* (2018-04-18 22:58 UTC)
Platform Info:
OS: macOS (x86_64-apple-darwin17.5.0)
CPU: Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
LAPACK: libopenblas64_
LIBM: libopenlibm
``````

#2

It is an effect of

``````julia> 0*Inf
NaN
``````

Now you might say that complex numbers should actually work on the one-point compactification (such that `Complex(Inf) == Complex(0,Inf)==-Complex(Inf)` and `Complex(0*Inf) === Complex(NaN) === Complex(Inf)+Complex(Inf)`) but this breaks transitivity of `Inf == Complex(Inf) == Complex(-Inf) == -Inf != Inf` and would probably be quite annoying/slow to code.

#3

I’m afraid I don’t understand much of what you wrote @foobar_lv2.

Does that explain the below?

``````julia> Complex{Bool}(im)*Float64(Inf)
0.0 + Inf*im

julia> Complex{Float64}(im)*Float64(Inf)
NaN + Inf*im
``````

#4

There is a special case for

``````julia> false*Inf
0.0
``````

This is the case even though 0==false. Arithmetic in julia is almost never well defined modulo `isequal` or `==`. You need to compare `typeof(x)==typeof(y) && isequal(x,y)` in order to get well-definedness. Excepting weird guys like `BigInt` and `BigFloat`, you can also check `===`. User-defined notions of equality that allow objects of different types to be equal are common in many languages, e.g. php or javascript (ok, I have some beef with this core decision, but for better or worse `1==1.0` is gonna stay and we have to live with it).

Let’s see what the two versions you had boil down to:

``````1*(im*Inf) = 1* Complex(0.0,Inf) = Complex(1*0.0, 1*Inf) = Complex(0.0,Inf)

(1*im)*Inf = Complex(0,1)*Inf = Complex(0*Inf, 1*Inf)=Complex(NaN,Inf)
``````

``````julia> Complex(1)*(im*Inf)
NaN + Inf*im

julia> Complex(true)*(im*Inf)
0.0 + Inf*im
``````

#5

The definition of `*(::Bool, ::Number)` has the following comment attached to it:

``````# make `false` a "strong zero": false*NaN == 0.0
``````

Since `im` is a `Complex{Bool}`, its real part is a “strong zero”, so the product `im*Inf` will have a zero in the real part. However, if `im` is converted to any other `Complex` type before the multiplication with `Inf`, then the real part will be NaN.

``````julia> im*Inf
0.0 + Inf*im

julia> (UInt8(1)*im)*Inf
NaN + Inf*im

julia> (im+0)*Inf
NaN + Inf*im

julia> Complex{Float64}(im)*Inf
NaN + Inf*im
``````

One could re-define

``````Base.:*(z::Complex{Bool}, x::T) where T<:Real = Complex(T(real(z)) * x, T(imag(z)) * x)
``````

which would make `im*Inf` return the same result as the other three examples…

#6

My original gut feeling is that `im` is just the imaginary unit, by which I mean purely imaginary without even a zero real part. Just as a float has no concept of an imaginary component, or complex has no concept of quarternions etc. If it’s purely the imaginary unit there is no zero for multiplication by `Inf`, and hence there is no `NaN`.

#7

Right. But, implementing an imaginary data type has apparently not been found practically and broadly useful in general numerical computer languages.

#8

I suppose I’m just drawing the distinction between an imaginary number and a complex number. Perhaps an improved description for the im documentation might be:

The imaginary unit as a complex number with zero real part.

Maybe the c++ macro is why I think this. But I haven’t checked it’s behaviour associated with `Inf` and `NaN`.

#9

The imaginary unit is a complex number. Don’t you think mathematics and implementation align here? Also I actually like that `im` has a strong real zero, making it behave closer to a mathematical constant than to a measured number.

#10

Yes, I agree it could be more clear. “the imaginary unit” might mean that there is a type `Imaginary`. Here is the definition

``````const im = Complex(false, true)
``````

#11

I’m not a trained mathematician, which might be where there is a difference in terminology.

`i` is the imaginary unit, which is the unit vector in the imaginary direction. Only tacitly is it an imaginary number. It’s the (non-existent?) difference between `0+1i` and just `i`.

#12

I’m a complete layman on these matters, but your post reminded me of the RiemannComplexNumbers.jl package – I thought I’d mention it in case it helps.

edit: and maybe some of the comments on #20924 could be related as well.

#13

Great! That’ll do the trick.