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 28 * Most functions are R-like: 29 * For example prod(a1,a2) computes an array c such that 30 * for (i=0;i<a1.length;i++) c[i] = a1[i]*a2[i]; 31 * 32 **/ 33 JXG.Math.Statistics = {}; 34 35 JXG.Math.Statistics.sum = function(arr) { 36 var i, len, res = 0; 37 38 for(i=0, len=arr.length; i<len; i++) { 39 res += arr[i]; 40 } 41 return res; 42 }; 43 44 JXG.Math.Statistics.prod = function(arr) { 45 var i, len, res = 1; 46 47 for(i=0, len=arr.length; i<len; i++) { 48 res *= arr[i]; 49 } 50 return res; 51 }; 52 53 JXG.Math.Statistics.mean = function(arr) { 54 if (arr.length>0) { 55 return this.sum(arr)/arr.length; 56 } else { 57 return 0.0; 58 } 59 }; 60 61 JXG.Math.Statistics.median = function(arr) { 62 var tmp, len; 63 64 if (arr.length>0) { 65 tmp = arr.slice(0,arr.length); 66 tmp.sort(function(a,b){return a-b;}); 67 len = tmp.length; 68 if (len%2==1) { 69 return tmp[parseInt(len*0.5)]; 70 } else{ 71 return (tmp[len*0.5-1]+tmp[len*0.5])*0.5; 72 } 73 } else { 74 return 0.0; 75 } 76 }; 77 78 /** 79 * bias-corrected sample variance 80 */ 81 JXG.Math.Statistics.variance = function(arr) { 82 var m, res, i, len; 83 84 if (arr.length>1) { 85 m = this.mean(arr); 86 res = 0; 87 for(i=0, len=arr.length; i<len; i++) { 88 res += (arr[i]-m)*(arr[i]-m); 89 } 90 return res/(arr.length-1); 91 } else { 92 return 0.0; 93 } 94 }; 95 96 JXG.Math.Statistics.sd = function(arr) { 97 return Math.sqrt(this.variance(arr)); 98 }; 99 100 JXG.Math.Statistics.weightedMean = function(arr,w) { 101 if (arr.length!=w.length) { return; } 102 if (arr.length>0) { 103 return this.mean(this.multiply(arr,w)); 104 } else { 105 return 0.0; 106 } 107 }; 108 109 JXG.Math.Statistics.max = function(arr) { 110 var res, i, len; 111 112 if (arr.length==0) { return NaN; } 113 res = arr[0]; 114 for(i=1, len=arr.length; i<len; i++) { 115 res = (arr[i]>res)?(arr[i]):res; 116 } 117 return res; 118 }; 119 120 JXG.Math.Statistics.min = function(arr) { 121 var res, i, len; 122 123 if (arr.length==0) { return NaN; } 124 res = arr[0]; 125 for(i=1, len=arr.length; i<len; i++) { 126 res = (arr[i]<res)?(arr[i]):res; 127 } 128 return res; 129 }; 130 131 /** 132 * R-style functions 133 */ 134 JXG.Math.Statistics.range = function(arr) { 135 return [this.min(arr),this.max(arr)]; 136 }; 137 138 JXG.Math.Statistics.diff = function(arr) { // ????? 139 return arr; 140 }; 141 142 JXG.Math.Statistics.min = function(arr) { 143 var res, i, len; 144 145 if (arr.length==0) { return NaN; } 146 res = arr[0]; 147 for(i=1, len=arr.length; i<len; i++) { 148 res = (arr[i]<res)?(arr[i]):res; 149 } 150 return res; 151 }; 152 153 JXG.Math.Statistics.abs = function(arr) { // This can be generalized with Prototype.js and should be done for all Math. methods 154 var i, len, res = []; 155 if (typeof JXG.isArray(arr1)) { 156 for (i=0, len=arr.length;i<len;i++) { res[i] = Math.abs(arr[i]); } 157 } else if (typeof arr=='number') { 158 return Math.abs(arr); 159 } else { 160 res = null; 161 } 162 return res; 163 }; 164 165 JXG.Math.Statistics.add = function(arr1,arr2) { 166 var i, len, res = []; 167 168 if (typeof JXG.isArray(arr1) && typeof arr2=='number') { 169 for (i=0, len=arr1.length;i<len;i++) { res[i] = arr1[i]+arr2; } 170 } else if (typeof arr1=='number' && typeof JXG.isArray(arr2)) { 171 for (i=0, len=arr2.length;i<len;i++) { res[i] = arr1+arr2[i]; } 172 } else if (typeof JXG.isArray(arr1) && typeof JXG.isArray(arr2)) { 173 for (i=0, len=Math.min(arr1.length,arr2.length);i<len;i++) { res[i] = arr1[i]+arr2[i]; } 174 } else if (typeof arr1=='number' && typeof arr2=='number') { 175 res = arr1+arr2; 176 } else { 177 res = null; 178 } 179 return res; 180 }; 181 182 JXG.Math.Statistics.divide = function(arr1,arr2) { 183 var i, len, res = []; 184 185 if (typeof JXG.isArray(arr1) && typeof arr2=='number') { 186 for (i=0, len=arr1.length;i<len;i++) { res[i] = arr1[i]/arr2; } 187 } else if (typeof arr1=='number' && typeof JXG.isArray(arr2)) { 188 for (i=0, len=arr2.length;i<len;i++) { res[i] = arr1/arr2[i]; } 189 } else if (typeof JXG.isArray(arr1) && typeof JXG.isArray(arr2)) { 190 for (i=0, len=Math.min(arr1.length,arr2.length);i<len;i++) { res[i] = arr1[i]/arr2[i]; } 191 } else if (typeof arr1=='number' && typeof arr2=='number') { 192 res = arr1/arr2; 193 } else { 194 res = null; 195 } 196 return res; 197 }; 198 199 JXG.Math.Statistics.mod = function(arr1,arr2) { 200 var i, len, res = []; 201 202 if (typeof JXG.isArray(arr1) && typeof arr2=='number') { 203 for (i=0, len=arr1.length;i<len;i++) { res[i] = arr1[i]%arr2; } 204 } else if (typeof arr1=='number' && typeof JXG.isArray(arr2)) { 205 for (i=0, len=arr2.length;i<len;i++) { res[i] = arr1%arr2[i]; } 206 } else if (typeof JXG.isArray(arr1) && typeof JXG.isArray(arr2)) { 207 for (i=0, len=Math.min(arr1.length,arr2.length);i<len;i++) { res[i] = arr1[i]%arr2[i]; } 208 } else if (typeof arr1=='number' && typeof arr2=='number') { 209 res = arr1%arr2; 210 } else { 211 res = null; 212 } 213 return res; 214 }; 215 216 JXG.Math.Statistics.multiply = function(arr1,arr2) { 217 var i, len, res = []; 218 219 if (typeof JXG.isArray(arr1) && typeof arr2=='number') { 220 for (i=0, len=arr1.length;i<len;i++) { res[i] = arr1[i]*arr2; } 221 } else if (typeof arr1=='number' && typeof JXG.isArray(arr2)) { 222 for (i=0, len=arr2.length;i<len;i++) { res[i] = arr1*arr2[i]; } 223 } else if (typeof JXG.isArray(arr1) && typeof JXG.isArray(arr2)) { 224 for (i=0, len=Math.min(arr1.length,arr2.length);i<len;i++) { res[i] = arr1[i]*arr2[i]; } 225 } else if (typeof arr1=='number' && typeof arr2=='number') { 226 res = arr1*arr2; 227 } else { 228 res = null; 229 } 230 return res; 231 }; 232 233 JXG.Math.Statistics.subtract = function(arr1,arr2) { 234 var i, len, res = []; 235 236 if (typeof JXG.isArray(arr1) && typeof arr2=='number') { 237 for (i=0, len=arr1.length;i<len;i++) { res[i] = arr1[i]-arr2; } 238 } else if (typeof arr1=='number' && typeof JXG.isArray(arr2)) { 239 for (i=0, len=arr2.length;i<len;i++) { res[i] = arr1-arr2[i]; } 240 } else if (typeof JXG.isArray(arr1) && typeof JXG.isArray(arr2)) { 241 for (i=0, len=Math.min(arr1.length,arr2.length);i<len;i++) { res[i] = arr1[i]-arr2[i]; } 242 } else if (typeof arr1=='number' && typeof arr2=='number') { 243 res = arr1-arr2; 244 } else { 245 res = null; 246 } 247 return res; 248 }; 249