Negative Zero
It really works this way.
JavaScript, and JSON, get a lot of heat for some strange corners of floating point math.
But they really just follow IEEE 754.
This demo illustrates Signed zero.
Yeah, it’s in there, whether you like it or not.
import math
import cmath
pos_zero = +0.0
neg_zero = -0.0
print(f"Standard equality check: {pos_zero == neg_zero}") # True
print(f"Sign of pos_zero: {math.copysign(1, pos_zero)}") # 1.0
print(f"Sign of neg_zero: {math.copysign(1, neg_zero)}") # -1.0
print("\n--- 1. atan2 and the Sign of Zero ---")
# Python raises ZeroDivisionError for 1.0 / 0.0 instead of
# returning an IEEE infinity, but atan2 still sees the sign.
print(f"atan2(+0.0, -1.0) = {math.atan2(pos_zero, -1.0)}") # pi
print(f"atan2(-0.0, -1.0) = {math.atan2(neg_zero, -1.0)}") # -pi
print("\n--- 2. Branch Cuts in Complex Math ---")
# The square root of a negative complex zero behaves differently
# depending on which direction you approach the origin from.
print(f"Square root of (-1 + 0.0j): {cmath.sqrt(complex(-1, pos_zero))}") # 1j
print(f"Square root of (-1 - 0.0j): {cmath.sqrt(complex(-1, neg_zero))}")
This program prints:
Standard equality check: True
Sign of pos_zero: 1.0
Sign of neg_zero: -1.0
--- 1. atan2 and the Sign of Zero ---
atan2(+0.0, -1.0) = 3.141592653589793
atan2(-0.0, -1.0) = -3.141592653589793
--- 2. Branch Cuts in Complex Math ---
Square root of (-1 + 0.0j): 1j
Square root of (-1 - 0.0j): -1j
🚡