1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.compatibility.common.util; 18 19 import java.util.Arrays; 20 21 /** 22 * Utilities for doing statistics 23 */ 24 public class Stat { 25 /** 26 * Private constructor for static class. 27 */ Stat()28 private Stat() {} 29 30 /** 31 * Collection of statistical propertirs like average, max, min, and stddev 32 */ 33 public static class StatResult { 34 public double mAverage; 35 public double mMin; 36 public double mMax; 37 public double mStddev; 38 public int mDataCount; StatResult(double average, double min, double max, double stddev, int dataCount)39 public StatResult(double average, double min, double max, double stddev, int dataCount) { 40 mAverage = average; 41 mMin = min; 42 mMax = max; 43 mStddev = stddev; 44 mDataCount = dataCount; 45 } 46 } 47 48 /** 49 * Calculate statistics properties likes average, min, max, and stddev for the given array 50 */ getStat(double[] data)51 public static StatResult getStat(double[] data) { 52 double average = data[0]; 53 double min = data[0]; 54 double max = data[0]; 55 for (int i = 1; i < data.length; i++) { 56 average += data[i]; 57 if (data[i] > max) { 58 max = data[i]; 59 } 60 if (data[i] < min) { 61 min = data[i]; 62 } 63 } 64 average /= data.length; 65 double sumOfSquares = 0.0; 66 for (int i = 0; i < data.length; i++) { 67 double diff = average - data[i]; 68 sumOfSquares += diff * diff; 69 } 70 double variance = sumOfSquares / (data.length - 1); 71 double stddev = Math.sqrt(variance); 72 return new StatResult(average, min, max, stddev, data.length); 73 } 74 75 /** 76 * Calculate statistics properties likes average, min, max, and stddev for the given array 77 * while rejecting outlier +/- median * rejectionThreshold. 78 * rejectionThreshold should be bigger than 0.0 and be lowerthan 1.0 79 */ getStatWithOutlierRejection(double[] data, double rejectionThreshold)80 public static StatResult getStatWithOutlierRejection(double[] data, double rejectionThreshold) { 81 double[] dataCopied = Arrays.copyOf(data, data.length); 82 Arrays.sort(dataCopied); 83 int medianIndex = dataCopied.length / 2; 84 double median; 85 if (dataCopied.length % 2 == 1) { 86 median = dataCopied[medianIndex]; 87 } else { 88 median = (dataCopied[medianIndex - 1] + dataCopied[medianIndex]) / 2.0; 89 } 90 double thresholdMin = median * (1.0 - rejectionThreshold); 91 double thresholdMax = median * (1.0 + rejectionThreshold); 92 93 double[] validData = new double[data.length]; 94 int index = 0; 95 for (int i = 0; i < data.length; i++) { 96 if ((data[i] > thresholdMin) && (data[i] < thresholdMax)) { 97 validData[index] = data[i]; 98 index++; 99 } 100 // TODO report rejected data 101 } 102 return getStat(Arrays.copyOf(validData, index)); 103 } 104 105 /** 106 * return the average value of the passed array 107 */ getAverage(double[] data)108 public static double getAverage(double[] data) { 109 double sum = data[0]; 110 for (int i = 1; i < data.length; i++) { 111 sum += data[i]; 112 } 113 return sum / data.length; 114 } 115 116 /** 117 * return the minimum value of the passed array 118 */ getMin(double[] data)119 public static double getMin(double[] data) { 120 double min = data[0]; 121 for (int i = 1; i < data.length; i++) { 122 if (data[i] < min) { 123 min = data[i]; 124 } 125 } 126 return min; 127 } 128 129 /** 130 * return the maximum value of the passed array 131 */ getMax(double[] data)132 public static double getMax(double[] data) { 133 double max = data[0]; 134 for (int i = 1; i < data.length; i++) { 135 if (data[i] > max) { 136 max = data[i]; 137 } 138 } 139 return max; 140 } 141 142 /** 143 * Calculate rate per sec for given change happened during given timeInMSec. 144 * timeInSec with 0 value will be changed to small value to prevent divide by zero. 145 * @param change total change of quality for the given duration timeInMSec. 146 * @param timeInMSec 147 */ calcRatePerSec(double change, double timeInMSec)148 public static double calcRatePerSec(double change, double timeInMSec) { 149 if (timeInMSec == 0) { 150 return change * 1000.0 / 0.001; // do not allow zero 151 } else { 152 return change * 1000.0 / timeInMSec; 153 } 154 } 155 156 /** 157 * array version of calcRatePerSecArray 158 */ calcRatePerSecArray(double change, double[] timeInMSec)159 public static double[] calcRatePerSecArray(double change, double[] timeInMSec) { 160 double[] result = new double[timeInMSec.length]; 161 change *= 1000.0; 162 for (int i = 0; i < timeInMSec.length; i++) { 163 if (timeInMSec[i] == 0) { 164 result[i] = change / 0.001; 165 } else { 166 result[i] = change / timeInMSec[i]; 167 } 168 } 169 return result; 170 } 171 172 /** 173 * Get the value of the 95th percentile using nearest rank algorithm. 174 */ get95PercentileValue(double[] values)175 public static double get95PercentileValue(double[] values) { 176 Arrays.sort(values); 177 // zero-based array index 178 int index = (int) Math.round(values.length * 0.95 + .5) - 1; 179 return values[index]; 180 } 181 182 } 183