/* from @antv */

/**
 * Our default sum is the [Kahan-Babuska algorithm](https://pdfs.semanticscholar.org/1760/7d467cda1d0277ad272deb2113533131dc09.pdf).
 * This method is an improvement over the classical
 * [Kahan summation algorithm](https://en.wikipedia.org/wiki/Kahan_summation_algorithm).
 * It aims at computing the sum of a list of numbers while correcting for
 * floating-point errors. Traditionally, sums are calculated as many
 * successive additions, each one with its own floating-point roundoff. These
 * losses in precision add up as the number of numbers increases. This alternative
 * algorithm is more accurate than the simple way of calculating sums by simple
 * addition.
 *
 * This runs on `O(n)`, linear time in respect to the array.
 *
 * @param {Array<number>} x input
 * @return {number} sum of all input numbers
 * @example
 * sum([1, 2, 3]); // => 6
 */
function sumFnc(x: number[]): number {
  // If the array is empty, we needn't bother computing its sum
  if (x.length === 0) {
      return 0;
  }

  // Initializing the sum as the first number in the array
  let sum = x[0];

  // Keeping track of the floating-point error correction
  let correction = 0;

  let transition;

  for (let i = 1; i < x.length; i++) {
      transition = sum + x[i];

      // Here we need to update the correction in a different fashion
      // if the new absolute value is greater than the absolute sum
      if (Math.abs(sum) >= Math.abs(x[i])) {
          correction += sum - transition + x[i];
      } else {
          correction += x[i] - transition + sum;
      }

      sum = transition;
  }

  // Returning the corrected sum
  return sum + correction;
}

export default sumFnc;
