spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← All files
name: dist/Formulas/Range.js
-rw-r--r--
5871
  1"use strict";
  2exports.__esModule = true;
  3var ArgsChecker_1 = require("../Utilities/ArgsChecker");
  4var Filter_1 = require("../Utilities/Filter");
  5var TypeConverter_1 = require("../Utilities/TypeConverter");
  6var Errors_1 = require("../Errors");
  7var MathHelpers_1 = require("../Utilities/MathHelpers");
  8/**
  9 * Calculates the frequency distribution of a range into specified classes or "bins".
 10 * @param range - to get frequency for.
 11 * @param bins - or classes.
 12 * @returns {Array<number>}
 13 * @constructor
 14 * TODO: Returns ColumnArray (values stacked in Y-direction)
 15 */
 16var FREQUENCY = function (range, bins) {
 17    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "FREQUENCY");
 18    if (!Array.isArray(bins)) {
 19        bins = [bins];
 20    }
 21    if (!Array.isArray(range)) {
 22        range = [range];
 23    }
 24    bins = Filter_1.Filter.flattenAndThrow(bins).map(function (value) {
 25        return TypeConverter_1.TypeConverter.firstValueAsNumber(value);
 26    }).sort(function (a, b) {
 27        return a - b;
 28    });
 29    range = Filter_1.Filter.flattenAndThrow(range).map(function (value) {
 30        return TypeConverter_1.TypeConverter.firstValueAsNumber(value);
 31    }).sort(function (a, b) {
 32        return a - b;
 33    });
 34    var n = range.length;
 35    var b = bins.length;
 36    var r = [];
 37    for (var i = 0; i <= b; i++) {
 38        r[i] = 0;
 39        for (var j = 0; j < n; j++) {
 40            if (i === 0) {
 41                if (range[j] <= bins[0]) {
 42                    r[0] += 1;
 43                }
 44            }
 45            else if (i < b) {
 46                if (range[j] > bins[i - 1] && range[j] <= bins[i]) {
 47                    r[i] += 1;
 48                }
 49            }
 50            else if (i === b) {
 51                if (range[j] > bins[b - 1]) {
 52                    r[b] += 1;
 53                }
 54            }
 55        }
 56    }
 57    return r;
 58};
 59exports.FREQUENCY = FREQUENCY;
 60/**
 61 * Given partial data with exponential growth, fits and ideal exponential growth trend, and predicts future values. For
 62 * more information see: https://xkcd.com/1102/
 63 * @param knownY - The range or array containing the dependent, y, values that are known, and will be used to fit an
 64 * ideal exponential growth curve.
 65 * @param knownX - OPTIONAL - The range or values of the independent variables that correspond to knownY.
 66 * @param newX - OPTIONAL - The range, values, or data-points to return the y-values on the ideal curve fit.
 67 * @param shouldUseConstant - OPTIONAL - True by default. Given an exponential function y = b*m^x, should this function
 68 * calculate b?
 69 * @returns {Array}
 70 * @constructor
 71 * TODO: Returns RowArray (values stacked in X-direction)
 72 */
 73var GROWTH = function (knownY, knownX, newX, shouldUseConstant) {
 74    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 4, "GROWTH");
 75    // Credits: Ilmari Karonen, FormulaJs (https://github.com/sutoiku/formula.js/)
 76    knownY = Filter_1.Filter.flattenAndThrow(knownY).map(function (value) {
 77        if (typeof value !== "number") {
 78            throw new Errors_1.ValueError("Function GROWTH parameter 1 expects number values. But '" + value + "' is " + (typeof value)
 79                + " and cannot be coerced to a number.");
 80        }
 81        return value;
 82    });
 83    // Default values for optional parameters:
 84    if (arguments.length < 2) {
 85        knownX = [];
 86        for (var i = 1; i <= knownY.length; i++) {
 87            knownX.push(i);
 88        }
 89    }
 90    if (arguments.length < 3) {
 91        newX = [];
 92        for (var i = 1; i <= knownY.length; i++) {
 93            newX.push(i);
 94        }
 95    }
 96    if (arguments.length < 4) {
 97        shouldUseConstant = true || shouldUseConstant;
 98    }
 99    // Calculate sums over the data:
100    var n = knownY.length;
101    var avg_x = 0;
102    var avg_y = 0;
103    var avg_xy = 0;
104    var avg_xx = 0;
105    for (var i = 0; i < n; i++) {
106        var x = knownX[i];
107        var y = Math.log(knownY[i]);
108        avg_x += x;
109        avg_y += y;
110        avg_xy += x * y;
111        avg_xx += x * x;
112    }
113    avg_x /= n;
114    avg_y /= n;
115    avg_xy /= n;
116    avg_xx /= n;
117    // Compute linear regression coefficients:
118    var beta;
119    var alpha;
120    if (shouldUseConstant) {
121        beta = (avg_xy - avg_x * avg_y) / (avg_xx - avg_x * avg_x);
122        alpha = avg_y - beta * avg_x;
123    }
124    else {
125        beta = avg_xy / avg_xx;
126        alpha = 0;
127    }
128    // Compute and return result array:
129    var new_y = [];
130    for (var i = 0; i < newX.length; i++) {
131        new_y.push(Math.exp(alpha + beta * newX[i]));
132    }
133    return new_y;
134};
135exports.GROWTH = GROWTH;
136/**
137 * Returns the parameters of a linear trend.
138 * @param dataY - The range of data representing Y values.
139 * @param dataX - The range of data representing X values.
140 * @returns {number[]}
141 * @constructor
142 */
143var LINEST = function (dataY, dataX) {
144    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "LINEST");
145    var rangeY = Filter_1.Filter.flattenAndThrow(dataY).map(function (value) {
146        return TypeConverter_1.TypeConverter.valueToNumber(value);
147    });
148    var rangeX = Filter_1.Filter.flattenAndThrow(dataX).map(function (value) {
149        return TypeConverter_1.TypeConverter.valueToNumber(value);
150    });
151    if (rangeX.length < 2) {
152        throw new Errors_1.NAError("LINEST requires more data points. Expected: 2, found: " + rangeX.length + ".");
153    }
154    if (rangeY.length < 2) {
155        throw new Errors_1.NAError("LINEST requires more data points. Expected: 2, found: " + rangeY.length + ".");
156    }
157    var xMean = MathHelpers_1.mean(rangeX);
158    var yMean = MathHelpers_1.mean(rangeY);
159    var n = rangeX.length;
160    var num = 0;
161    var den = 0;
162    for (var i = 0; i < n; i++) {
163        num += (rangeX[i] - xMean) * (rangeY[i] - yMean);
164        den += Math.pow(rangeX[i] - xMean, 2);
165    }
166    var m = num / den;
167    var b = yMean - m * xMean;
168    return [m, b];
169};
170exports.LINEST = LINEST;