Class CompensatedSum

java.lang.Object
dev.frostlake.functions.aggregate.CompensatedSum

public final class CompensatedSum extends Object
A running sum of doubles with Kahan compensation, which is the closest single rule to how the account adds them.

Naive left-to-right addition is NOT what live does, and the cells that show it are cheap to reproduce: ten copies of 0.1::FLOAT sum to exactly 1 there — SUM(f) = 1 is TRUE — where naive addition gives 0.9999999999999999; seven tenths are 0.70000000000000006661 where naive addition gives 0.69999999999999995559; and a hundred or a thousand tenths are exactly 10 and 100. Compensated summation reproduces every one of those, the eleven-tenths cell, the averages that follow from them, and both cancellation sets (1e16 + 1 + 1 - 1e16 is 2, 1e16 + 1 - 1e16 is 0), while an exact decimal sum rounded once does not.

It is a model, not the account's code: the account's answer also depends on how the rows are partitioned, and one measured shape — six tenths read back from a table — comes out as naive addition would have it. The sum starts from a positive zero, as IEEE addition does, so a lone -0.0 sums to 0.

  • Constructor Details

    • CompensatedSum

      public CompensatedSum()
  • Method Details

    • add

      public void add(double term)
      Add one term.
      Parameters:
      term - the next value, in input order
    • reset

      public void reset()
      Forget every term.
    • isSeeded

      public boolean isSeeded()
      Whether any term has been added.
      Returns:
      true after the first term
    • value

      public double value()
      The sum so far.
      Returns:
      the compensated sum, or 0.0 before any term
    • correctedValue

      public double correctedValue()
      The sum so far with its last compensation applied: the rounding error of the latest addition, which value() carries forward unapplied, taken back out. SUM and AVG read an aggregate's sum this way, a running window reading value() instead (see PartialFloatSum), and the variance family reads its sums this way too (see SquaredSumMoments) — over 0.3 then 0.7 squared this is 0.57999999999999984901 where value() is 0.57999999999999996003.
      Returns:
      the corrected sum, or 0.0 before any term