Different results when using 1 and 1.0 in expression

d = (1+0im, 1.0+0im) (sqrt(exp(-d[1]) - 1),
                      sqrt(exp(-d[2]) - 1))
(0.0 + 0.7950600976206501im, 0.0 - 0.7950600976206501im)

also

d = (1+0im, 1.0+0im); (sqrt(exp(-d[1]) - 1.0),
                       sqrt(exp(-d[2]) - 1.0))
(0.0 + 0.7950600976206501im, 0.0 - 0.7950600976206501im)

On Julia 1.11.3.

I’m curious as to why the results are different. Might anyone provide some insight into this?

To allay accusations of the XY problem, the context here is solving the unstable Bernoulli differential equation ẏ = by + y³, y(0) = 1, which has the closed-form solution

y(t, b) = 1im * √b * exp(t) / sqrt(exp(2b*t)/(1+b) - 1) # *(±1). Assuming +1.
y(-2, Complex(1))
0.1359592602682265 - 0.0im
y(-2, Complex(1.0))
-0.1359592602682265 + 0.0im

I could just cast everything to float, sure. However, I’d like to understand what’s going on, if possible.

I’m completely missing what’s different.

1 Like

Sorry, that could have been more clear. Using the integer 1 results in
0.0 + 0.7950600976206501im

Using the float 1.0 results in
0.0 - 0.7950600976206501im

The sign of the imaginary component is flipped.

Is it? They look the same to me.

Your simplified example doesn’t show what you want but the real one ultimately is a question of floating point being able to represent both positive and negative zeroes, whereas integers can’t.

1 Like

It’s taking a different branch cut of the square root because floating-point numbers have a signed zero but integers do not.

In particular, notice:

julia> -(1+0im) # Complex{Int}
-1 + 0im

julia> -(1.0+0im) # Complex{Float64}
-1.0 - 0.0im

Using 1.0+0im causes both real and imaginary parts to be promoted to Float64, i.e. it is equivalent to 1.0+0.0im. Then, negating it flips the sign of both parts, because floating point numbers keep track of a sign bit for ±0.0.

In most calculations, the sign bit of zero doesn’t matter, but it causes sqrt to choose a different branch cut for the square root of negative real numbers:

julia> sqrt(-1.0 + 0.0im)
0.0 + 1.0im

julia> sqrt(-1.0 - 0.0im)
0.0 - 1.0im

This is not specific to Julia — it is completely standardized by IEEE floating-point arithmetic. See also the famous article:

5 Likes

Thank you, I completely forgot that negative zero exists in floating point. That does clear it up for me.

Thank you for the article! I’ll take a look. I somehow forgot about negative zero in floats, and had I remembered, I’m not sure I’d have made the connection to what I was reading.

Thank you all for replying so quickly.