We should have a function detecting if two numbers have the same sign

We should have such a function!!
issign(x,y)

issign(-1,1) -->false
issign(1,-1) -->false
issign(1,1) -->true
issign(-1,-1) -->true

Why not just write this as sign(x) == sign(y)?

9 Likes

Any adequate solution using signbit()? One attempt:

 !signbit(x*y)

Or maybe better:

!(signbit(x) ⊻ signbit(y))
2 Likes

So what should the function return if both numbers are complex?

2 Likes

flipsign(x, y) >= 0 is close to a solution, except when x or y are null.

Sign of a complex number z is defined in the same way as for a real: z/abs(z). Then of course one can compare the resulting signs as one would do for a real number as well.

That said, it’s a valid concern! :wink:

How would that work? How do you compare for example the “signs” of z1 = 1 + im and z2 = 1 + 2im ? Dividing by the modulus doesn’t help…

(Not that it matters I think: the function would simply be undefined for complex numbers).

You could think of the sign of a complex number as the direction of the (unit) vector in the Re vs Im plane.

Therefore:

z1 = 2.0 + 2.0im
z2 = 1.0 + 1.0im
z3 = -1.0 - 1.0im
z4 = -1.0 + 1.0im

sign(z1) == sign(z2) #true
sign(z1) == sign(z3) #false
sign(z1) == sign(z4) #false

is the expected result and Julia provides it. And yes, that means that the sign of a complex number is not just -1, (0) or 1, but in fact still a complex number.

So conceptually there would be infinitely many different signs, and we have for example sign(1.0 + 1.0im) != sign(1.0 + 2.0im)? I’m not sure that would be useful. We can already do angle(z1) == angle(z2) to compare the directions (with the same caveat as below).

Also, the sign is part of the representation of (real) floating point numbers, and comparisons are often meaningful. For complex numbers it would be calculated with floating-point operations, and comparing the results for two numbers would be meaningless in general: they would often be unequal just because of floating-point inaccuracies. For example:

sign(z::Complex) = z/abs(z)

z1 = 1.0 + 0.1im;
z2 =       0.2im;
z3 = 1.0 + 0.3im;

julia> sign(z1+z2) == sign(z3)
false

Well, it’s just the mathematical definition of sign for complex numbers (as it’s normally defined and how it’s consequently defined in Julia); as such, it’s useful, because it follows the normal convention. Whether it’s what the OP needs is another question (to me at least).

The floating point precision problem does of course exist, but that’s what we have rational numbers for?

z1 = 1 + 1//10im
z2 = 2//10im
z3 = 1 + 3//10im
sign(z1+z2) == sign(z3) # true
1 Like

Ah I didn’t know this was a thing (I don’t think I’ve ever seen that used) and didn’t realized sign was already defined for complex numbers in Julia!

What about the number zero, 0?

?sign

sign(x)

  Return zero if x==0 and x/|x| otherwise (i.e., ±1 for real x).

followed by examples. So, sign(0) = 0 and sign(0.0 + 0.0im) = 0.0 + 0.0im.

2 Likes

The documentation for sign has a small inaccuracy. It doesn’t return zero(x) for negative zero:

julia> sign(-0.0)
-0.0

The documentation probably should say Return x if x==0...

3 Likes