Well, the standard says
When neither the inputs nor result are NaN, the sign of a product or quotient is the exclusive OR of the operands’ signs; the sign of a sum, or of a difference x − y regarded as a sum x + (−y), differs from at most one of the addends’ signs; and […]. These rules shall apply even when operands or results are zero or infinite.
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 under all rounding-direction attributes except roundTowardNegative; under that attribute, the sign of an exact zero sum (or difference) shall be −0. However, under all rounding-direction attributes, when x is zero, x + x and x − (−x) have the sign of x.
So +0 + +0 ⇒ +0
and -0 + -0 ⇒ -0
, but +0 + -0 ⇒ +0
and -0 + +0 ⇒ +0
.
That means that |x| 0.0 + x
is not identity because putting in -0
gives you +0
, and thus +0
is not an additive identity. But |x| -0.0 + x
does give you -0
if you put in -0
, as well as +0
if you put in +0
, making it an identity function, and -0
the additive identity.
You can also see this clearly in godbolt, as LLVM knows which is actually an identity, and optimizes based on that fact: https://rust.godbolt.org/z/saaWqchqx.
I mean, this part is really clear to me. You're using the addition monoid, so of course the result of the sum of an empty sequence should be the identity from that monoid. That's the only way you get x.sum()
and let (a, b) = x.split(i); a.sum() + b.sum()
to give you the same result.
And that's not just a theoretical property. It's exactly what you want so that you can sum a VecDeque
by summing the two as_slices()
and adding the result, for example.
(Well, except that floating-point addition isn't technically a monoid because it's non-associative, but that's a whole different problem. Sum::sum
, at least, at the trait level should obviously be defined to return the additive identity element when passed an empty iterator. TBH people probably would be more annoyed if we said you can't .sum()
floats -- they certainly complain plenty about the more important difference that's PartialOrd
!)