1 /** 2 Range-based statistic computations. 3 4 If you need real statistics, consider using the $(WEB github.com/dsimcha/dstats,Dstats) library. 5 */ 6 module gfm.math.statistics; 7 8 import std.range, 9 std.math; 10 11 /// Arithmetic mean. 12 double average(R)(R r) if (isInputRange!R) 13 { 14 if (r.empty) 15 return double.nan; 16 17 typeof(r.front()) sum = 0; 18 size_t count = 0; 19 foreach(e; r) 20 { 21 sum += e; 22 ++count; 23 } 24 return sum / count; 25 } 26 27 /// Minimum of a range. 28 double minElement(R)(R r) if (isInputRange!R) 29 { 30 // do like Javascript for an empty range 31 if (r.empty) 32 return double.infinity; 33 34 return minmax!("<", R)(r); 35 } 36 37 /// Maximum of a range. 38 double maxElement(R)(R r) if (isInputRange!R) 39 { 40 // do like Javascript for an empty range 41 if (r.empty) 42 return -double.infinity; 43 44 return minmax!(">", R)(r); 45 } 46 47 /// Variance of a range. 48 double variance(R)(R r) if (isForwardRange!R) 49 { 50 if (r.empty) 51 return double.nan; 52 53 auto avg = average(r.save); // getting the average 54 55 typeof(avg) sum = 0; 56 size_t count = 0; 57 foreach(e; r) 58 { 59 sum += (e - avg) ^^ 2; 60 ++count; 61 } 62 if (count <= 1) 63 return 0.0; 64 else 65 return (sum / (count - 1.0)); // using sample std deviation as estimator 66 } 67 68 /// Standard deviation of a range. 69 double standardDeviation(R)(R r) if (isForwardRange!R) 70 { 71 return sqrt(variance(r)); 72 } 73 74 private 75 { 76 typeof(R.front()) minmax(string op, R)(R r) if (isInputRange!R) 77 { 78 assert(!r.empty); 79 auto best = r.front(); 80 r.popFront(); 81 foreach(e; r) 82 { 83 mixin("if (e " ~ op ~ " best) best = e;"); 84 } 85 return best; 86 } 87 }