// This file is provided under The MIT License as part of RiptideNetworking. // Copyright (c) Tom Weiland // For additional information please see the included LICENSE.md file or view it on GitHub: // https://github.com/RiptideNetworking/Riptide/blob/main/LICENSE.md using System; using System.Linq; namespace Riptide.Utils { /// Represents a rolling series of numbers. public class RollingStat { /// The position in the array of the latest item. private int index; /// How many of the array's slots are in use. private int slotsFilled; /// private double mean; /// The sum of the mean subtracted from each value in the array. private double sumOfSquares; /// The array used to store the values. private readonly double[] array; /// The mean of the stat's values. public double Mean => mean; /// The variance of the stat's values. public double Variance => slotsFilled > 1 ? sumOfSquares / (slotsFilled - 1) : 0; /// The standard deviation of the stat's values. public double StandardDev { get { double variance = Variance; if (variance >= double.Epsilon) { double root = Math.Sqrt(variance); return double.IsNaN(root) ? 0 : root; } return 0; } } /// Initializes the stat. /// The number of values to store. public RollingStat(int sampleSize) { index = 0; slotsFilled = 0; mean = 0; sumOfSquares = 0; array = new double[sampleSize]; } /// Adds a new value to the stat. /// The value to add. public void Add(double value) { if (double.IsNaN(value) || double.IsInfinity(value)) return; index %= array.Length; double oldMean = mean; double oldValue = array[index]; array[index] = value; index++; if (slotsFilled == array.Length) { double delta = value - oldValue; mean += delta / slotsFilled; sumOfSquares += delta * (value - mean + (oldValue - oldMean)); } else { slotsFilled++; double delta = value - oldMean; mean += delta / slotsFilled; sumOfSquares += delta * (value - mean); } } /// public override string ToString() { if (slotsFilled == array.Length) return string.Join(",", array); return string.Join(",", array.Take(slotsFilled)); } } }