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 };