Is (x - x) always positive zero for doubles, or sometimes negative zero?
Solution 1:
x - x
can be +0.0
or NaN
. There are no other values it can take in IEEE 754 arithmetics in round-to-nearest (and in Java, the rounding mode is always round-to-nearest). The subtraction of two identical finite values is defined as producing +0.0
in this rounding mode. Mark Dickinson, in comments below, cites the IEEE 754 standard as saying, section 6.3:
When the sum of two operands with opposite signs (or the difference of two operands with like signs) is exactly zero, the sign of that sum (or difference) shall be +0 in all rounding-direction attributes except roundTowardNegative [...].
This page shows that in particular 0.0 - 0.0
and -0.0 - (-0.0)
are both +0.0
.
Infinities and NaN both produce NaN when subtracted from themselves.
Solution 2:
The SMT solver Z3 supports IEEE floating point arithmetic. Let's ask Z3 to find a case where x - x != 0
. It immediately finds NaN
as well as +-infinity
. Excluding those, there is no x
that satisfies that equation.
(set-logic QF_FPA)
(declare-const x (_ FP 11 53))
(declare-const r (_ FP 11 53))
(assert (and
(not (= x (as NaN (_ FP 11 53))))
(not (= x (as plusInfinity (_ FP 11 53))))
(not (= x (as minusInfinity (_ FP 11 53))))
(= r (- roundTowardZero x x))
(not (= r ((_ asFloat 11 53) roundTowardZero 0.0 0)))
))
(check-sat)
(get-model)
Z3 implements IEEE floating point arithmetic by converting all operations to boolean circuits and using the standard SAT solver to find a model. Barring any bugs in that translation or the SAT solver the result is perfectly precise.
Proof for...
- ...
roundTowardZero
: http://rise4fun.com/Z3/7H4 - ...
roundNearestTiesToEven
: http://rise4fun.com/Z3/Opl4W
Note the counterexample for the rounding mode roundTowardNegative
: http://rise4fun.com/Z3/T845. For a certain x
the result of x - x
is negative zero. Such a case can hardly be found by humans. Yet, with an SMT solver it is easy to find. We can change =
to ==
so that Z3 uses IEEE equality comparison semantics instead of exact equality. After that change, there is again no counter-example because -0 == +0
according to IEEE.
I tried making the rounding mode a variable. That would work in theory but Z3 has a bug here. For now we have to manually specify a hard-coded rounding mode. If we could make it a variable we could ask Z3 to prove this statement for all rounding modes in one query.