      1 /*
      2     Copyright 2008,2009
      3         Matthias Ehmann,
      4         Michael Gerhaeuser,
      5         Carsten Miller,
      6         Bianca Valentin,
      7         Alfred Wassermann,
      8         Peter Wilfahrt
      9
     10     This file is part of JSXGraph.
     11
     12     JSXGraph is free software: you can redistribute it and/or modify
     13     it under the terms of the GNU Lesser General Public License as published by
     14     the Free Software Foundation, either version 3 of the License, or
     15     (at your option) any later version.
     16
     17     JSXGraph is distributed in the hope that it will be useful,
     18     but WITHOUT ANY WARRANTY; without even the implied warranty of
     19     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20     GNU Lesser General Public License for more details.
     21
     22     You should have received a copy of the GNU Lesser General Public License
     23     along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
     24 */
     25
     26 /**
     27  * Functions for mathematical statistics. Most functions are like in the statistics package R.
     28  * @namespace
     29  */
     30 JXG.Math.Statistics = {
     31
     32     /**
     33      * Sums up all elements of the given array.
     34      * @param {Array} arr An array of numbers.
     35      * @returns {Number}
     36      */
     37     sum: function (arr) {
     38         var i, len = arr.length, res = 0;
     39
     40         for (i = 0; i<len; i++) {
     41             res += arr[i];
     42         }
     43         return res;
     44     },
     45
     46     /**
     47      * Multiplies all elements of the given array.
     48      * @param {Array} arr An array of numbers.
     49      * @returns {Number}
     50      */
     51     prod: function (arr) {
     52         var i, len = arr.length, res = 1;
     53
     54         for (i = 0; i < len; i++) {
     55             res *= arr[i];
     56         }
     57         return res;
     58     },
     59
     60     /**
     61      * Determines the mean value of the values given in an array.
     62      * @param {Array} arr
     63      * @returns {Number}
     64      */
     65     mean: function (arr) {
     66         if (arr.length > 0) {
     67             return this.sum(arr)/arr.length;
     68         } else {
     69             return 0.0;
     70         }
     71     },
     72
     73     /**
     74      * The median of a finite set of values is the value that divides the set
     75      * into two equal sized subsets.
     76      * @param {Array} arr The set of values.
     77      * @returns {Number}
     78      */
     79     median: function (arr) {
     80         var tmp, len;
     81
     82         if (arr.length > 0) {
     83             tmp = arr.slice(0);
     84             tmp.sort(function(a, b) {
     85                 return a - b;
     86             });
     87             len = tmp.length;
     88             if (len % 2 == 1) {
     89                 return tmp[parseInt(len*0.5)];
     90             } else{
     91                 return (tmp[len*0.5-1]+tmp[len*0.5])*0.5;
     92             }
     93         } else {
     94             return 0.0;
     95         }
     96     },
     97
     98     /**
     99      * Bias-corrected sample variance. A variance is a measure of how far a
    100      * set of numbers are spread out from each other.
    101      * @param {Array} arr
    102      * @returns {Number}
    103      */
    104     variance: function (arr) {
    105         var m, res, i, len = arr.length;
    106
    107         if (len > 1) {
    108             m = this.mean(arr);
    109             res = 0;
    110             for(i = 0; i < len; i++) {
    111                 res += (arr[i] - m) * (arr[i] - m);
    112             }
    113             return res/(arr.length - 1);
    114         } else {
    115             return 0.0;
    116         }
    117     },
    118
    119     /**
    120      * Determines the <strong>s</strong>tandard <strong>d</strong>eviation which shows how much
    121      * variation there is from the average value of a set of numbers.
    122      * @param {Array} arr
    123      * @returns {Number}
    124      */
    125     sd: function (arr) {
    126         return Math.sqrt(this.variance(arr));
    127     },
    128
    129     /**
    130      * Weighted mean value is basically the same as {@link JXG.Math.Statistics#mean} but here the values
    131      * are weighted, i.e. multiplied with another value called <em>weight</em>. The weight values are given
    132      * as a second array with the same length as the value array..
    133      * @throws {Error} If the dimensions of the arrays don't match.
    134      * @param {Array} arr Set of alues.
    135      * @param {Array} w Weight values.
    136      * @returns {Number}
    137      */
    138     weightedMean: function (arr, w) {
    139         if (arr.length != w.length) {
    140             throw new Error('JSXGraph error (Math.Statistics.weightedMean): Array dimension mismatch.');
    141         }
    142
    143         if (arr.length > 0) {
    144             return this.mean(this.multiply(arr, w));
    145         } else {
    146             return 0.0;
    147         }
    148     },
    149
    150     /**
    151      * Extracts the maximum value from the array.
    152      * @param {Array} arr
    153      * @returns {Number} The highest number from the array. It returns <tt>NaN</tt> if not every element could be
    154      * interpreted as a number and <tt>-Infinity</tt> if an empty array is given or no element could be interpreted
    155      * as a number.
    156      */
    157     max: function (arr) {
    158         return Math.max.apply(this, arr);
    159     },
    160
    161     /**
    162      * Extracts the minimum value from the array.
    163      * @param {Array} arr
    164      * @returns {Number} The lowest number from the array. It returns <tt>NaN</tt> if not every element could be
    165      * interpreted as a number and <tt>Infinity</tt> if an empty array is given or no element could be interpreted
    166      * as a number.
    167      */
    168     min: function (arr) {
    169         return Math.min.apply(this, arr);
    170     },
    171
    172     /**
    173      * Determines the lowest and the highest value from the given array.
    174      * @param {Array} arr
    175      * @returns {Array} The minimum value as the first and the maximum value as the second value.
    176      */
    177     range: function (arr) {
    178         return [this.min(arr), this.max(arr)];
    179     },
    180
    181     /**
    182      * Determines the absolute value of every given value.
    183      * @param {Array|Number} arr
    184      * @returns {Array|Number}
    185      */
    186     abs: function (arr) {
    187         var i, len, res;
    188
    189         if (JXG.isArray(arr)) {
    190             len = arr.length;
    191             res = [];
    192
    193             for (i = 0; i < len; i++) {
    194                 res[i] = Math.abs(arr[i]);
    195             }
    196         } else {
    197             res = Math.abs(arr);
    198         }
    199
    200         return res;
    201     },
    202
    203     /**
    204      * Adds up two (sequences of) values. If one value is an array and the other one is a number the number
    205      * is added to every element of the array. If two arrays are given and the lengths don't match the shortest
    206      * length is taken.
    207      * @param {Array|Number} arr1
    208      * @param {Array|Number} arr2
    209      * @returns {Array|Number}
    210      */
    211     add: function (arr1, arr2) {
    212         var i, len, res = [];
    213
    214         if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
    215             len = arr1.length;
    216
    217             for (i = 0; i < len; i++) {
    218                 res[i] = arr1[i] + arr2;
    219             }
    220         } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
    221             len = arr2.length;
    222
    223             for (i = 0; i < len; i++) {
    224                 res[i] = arr1 + arr2[i];
    225             }
    226         } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
    227             len = Math.min(arr1.length, arr2.length);
    228
    229             for (i = 0; i < len; i++) {
    230                 res[i] = arr1[i] + arr2[i];
    231             }
    232         } else {
    233             res = arr1 + arr2;
    234         }
    235
    236         return res;
    237     },
    238
    239     /**
    240      * Divides two (sequences of) values. If two arrays are given and the lengths don't match the shortest length
    241      * is taken.
    242      * @param {Array|Number} arr1 Dividend
    243      * @param {Array|Number} arr2 Divisor
    244      * @returns {Array|Number}
    245      */
    246     div: function (arr1, arr2) {
    247         var i, len, res = [];
    248
    249         if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
    250             len = arr1.length;
    251
    252             for (i = 0; i < len; i++) {
    253                 res[i] = arr1[i] / arr2;
    254             }
    255         } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
    256             len = arr2.length;
    257
    258             for (i = 0; i < len; i++) {
    259                 res[i] = arr1 / arr2[i];
    260             }
    261         } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
    262             len = Math.min(arr1.length, arr2.length);
    263
    264             for (i = 0; i < len; i++) {
    265                 res[i] = arr1[i] / arr2[i];
    266             }
    267         } else {
    268             res = arr1 / arr2;
    269         }
    270
    271         return res;
    272     },
    273
    274     /**
    275      * @function
    276      * @deprecated Use {@link JXG.Math.Statistics#div} instead.
    277      */
    278     divide: JXG.shortcut(JXG.Math.Statistics, 'div'),
    279
    280     /**
    281      * Divides two (sequences of) values and returns the remainder. If two arrays are given and the lengths don't
    282      * match the shortest length is taken.
    283      * @param {Array|Number} arr1 Dividend
    284      * @param {Array|Number} arr2 Divisor
    285      * @param {Boolean} [math=false] Mathematical mod or symmetric mod? Default is symmetric, the JavaScript <tt>%</tt> operator.
    286      * @returns {Array|Number}
    287      */
    288     mod: function (arr1, arr2, math) {
    289         var i, len, res = [], mod = function (a, m) {
    290             return a % m;
    291         };
    292
    293         math = JXG.def(math, false);
    294
    295         if (math) {
    296             mod = JXG.Math.mod;
    297         }
    298
    299         if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
    300             len = arr1.length;
    301
    302             for (i = 0; i < len; i++) {
    303                 res[i] = mod(arr1[i], arr2);
    304             }
    305         } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
    306             len = arr2.length;
    307
    308             for (i = 0; i < len; i++) {
    309                 res[i] = mod(arr1, arr2[i]);
    310             }
    311         } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
    312             len = Math.min(arr1.length, arr2.length);
    313
    314             for (i = 0; i < len; i++) {
    315                 res[i] = mod(arr1[i], arr2[i]);
    316             }
    317         } else {
    318             res = mod(arr1, arr2);
    319         }
    320
    321         return res;
    322     },
    323
    324     /**
    325      * Multiplies two (sequences of) values. If one value is an array and the other one is a number the number
    326      * is multiplied to every element of the array. If two arrays are given and the lengths don't match the shortest
    327      * length is taken.
    328      * @param {Array|Number} arr1
    329      * @param {Array|Number} arr2
    330      * @returns {Array|Number}
    331      */
    332     multiply: function (arr1, arr2) {
    333         var i, len, res = [];
    334
    335         if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
    336             len = arr1.length;
    337
    338             for (i = 0; i < len; i++) {
    339                 res[i] = arr1[i] * arr2;
    340             }
    341         } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
    342             len = arr2.length;
    343
    344             for (i = 0; i < len; i++) {
    345                 res[i] = arr1 * arr2[i];
    346             }
    347         } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
    348             len = Math.min(arr1.length, arr2.length);
    349
    350             for (i = 0; i < len; i++) {
    351                 res[i] = arr1[i] * arr2[i];
    352             }
    353         } else {
    354             res = arr1 * arr2;
    355         }
    356
    357         return res;
    358     },
    359
    360     /**
    361      * Subtracts two (sequences of) values. If two arrays are given and the lengths don't match the shortest
    362      * length is taken.
    363      * @param {Array|Number} arr1 Minuend
    364      * @param {Array|Number} arr2 Subtrahend
    365      * @returns {Array|Number}
    366      */
    367     subtract: function (arr1, arr2) {
    368         var i, len, res = [];
    369
    370         if (JXG.isArray(arr1) && JXG.isNumber(arr2)) {
    371             len = arr1.length;
    372
    373             for (i = 0; i < len; i++) {
    374                 res[i] = arr1[i] - arr2;
    375             }
    376         } else if (JXG.isNumber(arr1) && JXG.isArray(arr2)) {
    377             len = arr2.length;
    378
    379             for (i = 0; i < len; i++) {
    380                 res[i] = arr1 - arr2[i];
    381             }
    382         } else if (JXG.isArray(arr1) && JXG.isArray(arr2)) {
    383             len = Math.min(arr1.length, arr2.length);
    384
    385             for (i = 0; i < len; i++) {
    386                 res[i] = arr1[i] - arr2[i];
    387             }
    388         } else {
    389             res = arr1 - arr2;
    390         }
    391
    392         return res;
    393     }
    394 };