1 /* 2 * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "memory/allocation.inline.hpp" 27 #include "utilities/debug.hpp" 28 #include "utilities/globalDefinitions.hpp" 29 #include "utilities/numberSeq.hpp" 30 31 AbsSeq::AbsSeq(double alpha) : 32 _num(0), _sum(0.0), _sum_of_squares(0.0), 33 _davg(0.0), _dvariance(0.0), _alpha(alpha) { 34 } 35 36 void AbsSeq::add(double val) { 37 if (_num == 0) { 38 // if the sequence is empty, the davg is the same as the value 39 _davg = val; 40 // and the variance is 0 41 _dvariance = 0.0; 42 } else { 43 // otherwise, calculate both 44 // Formula from "Incremental calculation of weighted mean and variance" by Tony Finch 45 // diff := x - mean 46 // incr := alpha * diff 47 // mean := mean + incr 48 // variance := (1 - alpha) * (variance + diff * incr) 49 // PDF available at https://fanf2.user.srcf.net/hermes/doc/antiforgery/stats.pdf 50 double diff = val - _davg; 51 double incr = _alpha * diff; 52 _davg += incr; 53 _dvariance = (1.0 - _alpha) * (_dvariance + diff * incr); 54 } 55 } 56 57 double AbsSeq::avg() const { 58 if (_num == 0) 59 return 0.0; 60 else 61 return _sum / total(); 62 } 63 64 double AbsSeq::variance() const { 65 if (_num <= 1) 66 return 0.0; 67 68 double x_bar = avg(); 69 double result = _sum_of_squares / total() - x_bar * x_bar; 70 if (result < 0.0) { 71 // due to loss-of-precision errors, the variance might be negative 72 // by a small bit 73 74 // guarantee(-0.1 < result && result < 0.0, 75 // "if variance is negative, it should be very small"); 76 result = 0.0; 77 } 78 return result; 79 } 80 81 double AbsSeq::sd() const { 82 double var = variance(); 83 guarantee( var >= 0.0, "variance should not be negative" ); 84 return sqrt(var); 85 } 86 87 double AbsSeq::davg() const { 88 return _davg; 89 } 90 91 double AbsSeq::dvariance() const { 92 if (_num <= 1) 93 return 0.0; 94 95 double result = _dvariance; 96 if (result < 0.0) { 97 // due to loss-of-precision errors, the variance might be negative 98 // by a small bit 99 100 guarantee(-0.1 < result && result < 0.0, 101 "if variance is negative, it should be very small"); 102 result = 0.0; 103 } 104 return result; 105 } 106 107 double AbsSeq::dsd() const { 108 double var = dvariance(); 109 guarantee( var >= 0.0, "variance should not be negative" ); 110 return sqrt(var); 111 } 112 113 NumberSeq::NumberSeq(double alpha) : 114 AbsSeq(alpha), _last(0.0), _maximum(0.0) { 115 } 116 117 bool NumberSeq::check_nums(NumberSeq *total, int n, NumberSeq **parts) { 118 for (int i = 0; i < n; ++i) { 119 if (parts[i] != nullptr && total->num() != parts[i]->num()) 120 return false; 121 } 122 return true; 123 } 124 125 void NumberSeq::add(double val) { 126 AbsSeq::add(val); 127 128 _last = val; 129 if (_num == 0) { 130 _maximum = val; 131 } else { 132 if (val > _maximum) 133 _maximum = val; 134 } 135 _sum += val; 136 _sum_of_squares += val * val; 137 ++_num; 138 } 139 140 141 TruncatedSeq::TruncatedSeq(int length, double alpha): 142 AbsSeq(alpha), _length(length), _next(0) { 143 _sequence = NEW_C_HEAP_ARRAY(double, _length, mtInternal); 144 for (int i = 0; i < _length; ++i) 145 _sequence[i] = 0.0; 146 } 147 148 TruncatedSeq::~TruncatedSeq() { 149 FREE_C_HEAP_ARRAY(double, _sequence); 150 } 151 152 void TruncatedSeq::add(double val) { 153 AbsSeq::add(val); 154 155 // get the oldest value in the sequence... 156 double old_val = _sequence[_next]; 157 // ...remove it from the sum and sum of squares 158 _sum -= old_val; 159 _sum_of_squares -= old_val * old_val; 160 161 // ...and update them with the new value 162 _sum += val; 163 _sum_of_squares += val * val; 164 165 // now replace the old value with the new one 166 _sequence[_next] = val; 167 _next = (_next + 1) % _length; 168 169 // only increase it if the buffer is not full 170 if (_num < _length) 171 ++_num; 172 173 guarantee( variance() > -1.0, "variance should be >= 0" ); 174 } 175 176 // can't easily keep track of this incrementally... 177 double TruncatedSeq::maximum() const { 178 if (_num == 0) 179 return 0.0; 180 double ret = _sequence[0]; 181 for (int i = 1; i < _num; ++i) { 182 double val = _sequence[i]; 183 if (val > ret) 184 ret = val; 185 } 186 return ret; 187 } 188 189 double TruncatedSeq::last() const { 190 if (_num == 0) 191 return 0.0; 192 unsigned last_index = (_next + _length - 1) % _length; 193 return _sequence[last_index]; 194 } 195 196 double TruncatedSeq::oldest() const { 197 if (_num == 0) 198 return 0.0; 199 else if (_num < _length) 200 // index 0 always oldest value until the array is full 201 return _sequence[0]; 202 else { 203 // since the array is full, _next is over the oldest value 204 return _sequence[_next]; 205 } 206 } 207 208 double TruncatedSeq::predict_next() const { 209 if (_num == 0) 210 return 0.0; 211 212 double num = (double) _num; 213 double x_squared_sum = 0.0; 214 double x_sum = 0.0; 215 double y_sum = 0.0; 216 double xy_sum = 0.0; 217 double x_avg = 0.0; 218 double y_avg = 0.0; 219 220 int first = (_next + _length - _num) % _length; 221 for (int i = 0; i < _num; ++i) { 222 double x = (double) i; 223 double y = _sequence[(first + i) % _length]; 224 225 x_squared_sum += x * x; 226 x_sum += x; 227 y_sum += y; 228 xy_sum += x * y; 229 } 230 x_avg = x_sum / num; 231 y_avg = y_sum / num; 232 233 double Sxx = x_squared_sum - x_sum * x_sum / num; 234 double Sxy = xy_sum - x_sum * y_sum / num; 235 double b1 = Sxy / Sxx; 236 double b0 = y_avg - b1 * x_avg; 237 238 return b0 + b1 * num; 239 } 240 241 242 // Printing/Debugging Support 243 244 void AbsSeq::dump() { dump_on(tty); } 245 246 void AbsSeq::dump_on(outputStream* s) { 247 s->print_cr("\t _num = %d, _sum = %7.3f, _sum_of_squares = %7.3f", 248 _num, _sum, _sum_of_squares); 249 s->print_cr("\t _davg = %7.3f, _dvariance = %7.3f, _alpha = %7.3f", 250 _davg, _dvariance, _alpha); 251 } 252 253 void NumberSeq::dump_on(outputStream* s) { 254 AbsSeq::dump_on(s); 255 s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f", _last, _maximum); 256 } 257 258 void TruncatedSeq::dump_on(outputStream* s) { 259 AbsSeq::dump_on(s); 260 s->print_cr("\t\t _length = %d, _next = %d", _length, _next); 261 for (int i = 0; i < _length; i++) { 262 if (i%5 == 0) { 263 s->cr(); 264 s->print("\t"); 265 } 266 s->print("\t[%d]=%7.3f", i, _sequence[i]); 267 } 268 s->cr(); 269 }