jdk
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
31AbsSeq::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
36void AbsSeq::add(double val) {37if (_num == 0) {38// if the sequence is empty, the davg is the same as the value39_davg = val;40// and the variance is 041_dvariance = 0.0;42} else {43// otherwise, calculate both44// Formula from "Incremental calculation of weighted mean and variance" by Tony Finch45// diff := x - mean46// incr := alpha * diff47// mean := mean + incr48// variance := (1 - alpha) * (variance + diff * incr)49// PDF available at https://fanf2.user.srcf.net/hermes/doc/antiforgery/stats.pdf50double diff = val - _davg;51double incr = _alpha * diff;52_davg += incr;53_dvariance = (1.0 - _alpha) * (_dvariance + diff * incr);54}55}
56
57double AbsSeq::avg() const {58if (_num == 0)59return 0.0;60else61return _sum / total();62}
63
64double AbsSeq::variance() const {65if (_num <= 1)66return 0.0;67
68double x_bar = avg();69double result = _sum_of_squares / total() - x_bar * x_bar;70if (result < 0.0) {71// due to loss-of-precision errors, the variance might be negative72// by a small bit73
74// guarantee(-0.1 < result && result < 0.0,75// "if variance is negative, it should be very small");76result = 0.0;77}78return result;79}
80
81double AbsSeq::sd() const {82double var = variance();83guarantee( var >= 0.0, "variance should not be negative" );84return sqrt(var);85}
86
87double AbsSeq::davg() const {88return _davg;89}
90
91double AbsSeq::dvariance() const {92if (_num <= 1)93return 0.0;94
95double result = _dvariance;96if (result < 0.0) {97// due to loss-of-precision errors, the variance might be negative98// by a small bit99
100guarantee(-0.1 < result && result < 0.0,101"if variance is negative, it should be very small");102result = 0.0;103}104return result;105}
106
107double AbsSeq::dsd() const {108double var = dvariance();109guarantee( var >= 0.0, "variance should not be negative" );110return sqrt(var);111}
112
113NumberSeq::NumberSeq(double alpha) :114AbsSeq(alpha), _last(0.0), _maximum(0.0) {115}
116
117bool NumberSeq::check_nums(NumberSeq *total, int n, NumberSeq **parts) {118for (int i = 0; i < n; ++i) {119if (parts[i] != nullptr && total->num() != parts[i]->num())120return false;121}122return true;123}
124
125void NumberSeq::add(double val) {126AbsSeq::add(val);127
128_last = val;129if (_num == 0) {130_maximum = val;131} else {132if (val > _maximum)133_maximum = val;134}135_sum += val;136_sum_of_squares += val * val;137++_num;138}
139
140
141TruncatedSeq::TruncatedSeq(int length, double alpha):142AbsSeq(alpha), _length(length), _next(0) {143_sequence = NEW_C_HEAP_ARRAY(double, _length, mtInternal);144for (int i = 0; i < _length; ++i)145_sequence[i] = 0.0;146}
147
148TruncatedSeq::~TruncatedSeq() {149FREE_C_HEAP_ARRAY(double, _sequence);150}
151
152void TruncatedSeq::add(double val) {153AbsSeq::add(val);154
155// get the oldest value in the sequence...156double old_val = _sequence[_next];157// ...remove it from the sum and sum of squares158_sum -= old_val;159_sum_of_squares -= old_val * old_val;160
161// ...and update them with the new value162_sum += val;163_sum_of_squares += val * val;164
165// now replace the old value with the new one166_sequence[_next] = val;167_next = (_next + 1) % _length;168
169// only increase it if the buffer is not full170if (_num < _length)171++_num;172
173guarantee( variance() > -1.0, "variance should be >= 0" );174}
175
176// can't easily keep track of this incrementally...
177double TruncatedSeq::maximum() const {178if (_num == 0)179return 0.0;180double ret = _sequence[0];181for (int i = 1; i < _num; ++i) {182double val = _sequence[i];183if (val > ret)184ret = val;185}186return ret;187}
188
189double TruncatedSeq::last() const {190if (_num == 0)191return 0.0;192unsigned last_index = (_next + _length - 1) % _length;193return _sequence[last_index];194}
195
196double TruncatedSeq::oldest() const {197if (_num == 0)198return 0.0;199else if (_num < _length)200// index 0 always oldest value until the array is full201return _sequence[0];202else {203// since the array is full, _next is over the oldest value204return _sequence[_next];205}206}
207
208double TruncatedSeq::predict_next() const {209if (_num == 0) {210// No data points, pick function: y = 0 + 0*x211return 0.0;212}213
214if (_num == 1) {215// Only one point P, pick function: y = P_y + 0*x216return _sequence[0];217}218
219double num = (double) _num;220double x_squared_sum = 0.0;221double x_sum = 0.0;222double y_sum = 0.0;223double xy_sum = 0.0;224double x_avg = 0.0;225double y_avg = 0.0;226
227int first = (_next + _length - _num) % _length;228for (int i = 0; i < _num; ++i) {229double x = (double) i;230double y = _sequence[(first + i) % _length];231
232x_squared_sum += x * x;233x_sum += x;234y_sum += y;235xy_sum += x * y;236}237x_avg = x_sum / num;238y_avg = y_sum / num;239
240double Sxx = x_squared_sum - x_sum * x_sum / num;241double Sxy = xy_sum - x_sum * y_sum / num;242double b1 = Sxy / Sxx;243double b0 = y_avg - b1 * x_avg;244
245return b0 + b1 * num;246}
247
248
249// Printing/Debugging Support
250
251void AbsSeq::dump() { dump_on(tty); }252
253void AbsSeq::dump_on(outputStream* s) {254s->print_cr("\t _num = %d, _sum = %7.3f, _sum_of_squares = %7.3f",255_num, _sum, _sum_of_squares);256s->print_cr("\t _davg = %7.3f, _dvariance = %7.3f, _alpha = %7.3f",257_davg, _dvariance, _alpha);258}
259
260void NumberSeq::dump_on(outputStream* s) {261AbsSeq::dump_on(s);262s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f", _last, _maximum);263}
264
265void TruncatedSeq::dump_on(outputStream* s) {266AbsSeq::dump_on(s);267s->print_cr("\t\t _length = %d, _next = %d", _length, _next);268for (int i = 0; i < _length; i++) {269if (i%5 == 0) {270s->cr();271s->print("\t");272}273s->print("\t[%d]=%7.3f", i, _sequence[i]);274}275s->cr();276}
277