1 | /* |
2 | * Copyright (c) 2001, 2014, 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 | _davg = (1.0 - _alpha) * val + _alpha * _davg; |
45 | double diff = val - _davg; |
46 | _dvariance = (1.0 - _alpha) * diff * diff + _alpha * _dvariance; |
47 | } |
48 | } |
49 | |
50 | double AbsSeq::avg() const { |
51 | if (_num == 0) |
52 | return 0.0; |
53 | else |
54 | return _sum / total(); |
55 | } |
56 | |
57 | double AbsSeq::variance() const { |
58 | if (_num <= 1) |
59 | return 0.0; |
60 | |
61 | double x_bar = avg(); |
62 | double result = _sum_of_squares / total() - x_bar * x_bar; |
63 | if (result < 0.0) { |
64 | // due to loss-of-precision errors, the variance might be negative |
65 | // by a small bit |
66 | |
67 | // guarantee(-0.1 < result && result < 0.0, |
68 | // "if variance is negative, it should be very small"); |
69 | result = 0.0; |
70 | } |
71 | return result; |
72 | } |
73 | |
74 | double AbsSeq::sd() const { |
75 | double var = variance(); |
76 | guarantee( var >= 0.0, "variance should not be negative" ); |
77 | return sqrt(var); |
78 | } |
79 | |
80 | double AbsSeq::davg() const { |
81 | return _davg; |
82 | } |
83 | |
84 | double AbsSeq::dvariance() const { |
85 | if (_num <= 1) |
86 | return 0.0; |
87 | |
88 | double result = _dvariance; |
89 | if (result < 0.0) { |
90 | // due to loss-of-precision errors, the variance might be negative |
91 | // by a small bit |
92 | |
93 | guarantee(-0.1 < result && result < 0.0, |
94 | "if variance is negative, it should be very small" ); |
95 | result = 0.0; |
96 | } |
97 | return result; |
98 | } |
99 | |
100 | double AbsSeq::dsd() const { |
101 | double var = dvariance(); |
102 | guarantee( var >= 0.0, "variance should not be negative" ); |
103 | return sqrt(var); |
104 | } |
105 | |
106 | NumberSeq::NumberSeq(double alpha) : |
107 | AbsSeq(alpha), _last(0.0), _maximum(0.0) { |
108 | } |
109 | |
110 | bool NumberSeq::check_nums(NumberSeq *total, int n, NumberSeq **parts) { |
111 | for (int i = 0; i < n; ++i) { |
112 | if (parts[i] != NULL && total->num() != parts[i]->num()) |
113 | return false; |
114 | } |
115 | return true; |
116 | } |
117 | |
118 | void NumberSeq::add(double val) { |
119 | AbsSeq::add(val); |
120 | |
121 | _last = val; |
122 | if (_num == 0) { |
123 | _maximum = val; |
124 | } else { |
125 | if (val > _maximum) |
126 | _maximum = val; |
127 | } |
128 | _sum += val; |
129 | _sum_of_squares += val * val; |
130 | ++_num; |
131 | } |
132 | |
133 | |
134 | TruncatedSeq::TruncatedSeq(int length, double alpha): |
135 | AbsSeq(alpha), _length(length), _next(0) { |
136 | _sequence = NEW_C_HEAP_ARRAY(double, _length, mtInternal); |
137 | for (int i = 0; i < _length; ++i) |
138 | _sequence[i] = 0.0; |
139 | } |
140 | |
141 | TruncatedSeq::~TruncatedSeq() { |
142 | FREE_C_HEAP_ARRAY(double, _sequence); |
143 | } |
144 | |
145 | void TruncatedSeq::add(double val) { |
146 | AbsSeq::add(val); |
147 | |
148 | // get the oldest value in the sequence... |
149 | double old_val = _sequence[_next]; |
150 | // ...remove it from the sum and sum of squares |
151 | _sum -= old_val; |
152 | _sum_of_squares -= old_val * old_val; |
153 | |
154 | // ...and update them with the new value |
155 | _sum += val; |
156 | _sum_of_squares += val * val; |
157 | |
158 | // now replace the old value with the new one |
159 | _sequence[_next] = val; |
160 | _next = (_next + 1) % _length; |
161 | |
162 | // only increase it if the buffer is not full |
163 | if (_num < _length) |
164 | ++_num; |
165 | |
166 | guarantee( variance() > -1.0, "variance should be >= 0" ); |
167 | } |
168 | |
169 | // can't easily keep track of this incrementally... |
170 | double TruncatedSeq::maximum() const { |
171 | if (_num == 0) |
172 | return 0.0; |
173 | double ret = _sequence[0]; |
174 | for (int i = 1; i < _num; ++i) { |
175 | double val = _sequence[i]; |
176 | if (val > ret) |
177 | ret = val; |
178 | } |
179 | return ret; |
180 | } |
181 | |
182 | double TruncatedSeq::last() const { |
183 | if (_num == 0) |
184 | return 0.0; |
185 | unsigned last_index = (_next + _length - 1) % _length; |
186 | return _sequence[last_index]; |
187 | } |
188 | |
189 | double TruncatedSeq::oldest() const { |
190 | if (_num == 0) |
191 | return 0.0; |
192 | else if (_num < _length) |
193 | // index 0 always oldest value until the array is full |
194 | return _sequence[0]; |
195 | else { |
196 | // since the array is full, _next is over the oldest value |
197 | return _sequence[_next]; |
198 | } |
199 | } |
200 | |
201 | double TruncatedSeq::predict_next() const { |
202 | if (_num == 0) |
203 | return 0.0; |
204 | |
205 | double num = (double) _num; |
206 | double x_squared_sum = 0.0; |
207 | double x_sum = 0.0; |
208 | double y_sum = 0.0; |
209 | double xy_sum = 0.0; |
210 | double x_avg = 0.0; |
211 | double y_avg = 0.0; |
212 | |
213 | int first = (_next + _length - _num) % _length; |
214 | for (int i = 0; i < _num; ++i) { |
215 | double x = (double) i; |
216 | double y = _sequence[(first + i) % _length]; |
217 | |
218 | x_squared_sum += x * x; |
219 | x_sum += x; |
220 | y_sum += y; |
221 | xy_sum += x * y; |
222 | } |
223 | x_avg = x_sum / num; |
224 | y_avg = y_sum / num; |
225 | |
226 | double Sxx = x_squared_sum - x_sum * x_sum / num; |
227 | double Sxy = xy_sum - x_sum * y_sum / num; |
228 | double b1 = Sxy / Sxx; |
229 | double b0 = y_avg - b1 * x_avg; |
230 | |
231 | return b0 + b1 * num; |
232 | } |
233 | |
234 | |
235 | // Printing/Debugging Support |
236 | |
237 | void AbsSeq::dump() { dump_on(tty); } |
238 | |
239 | void AbsSeq::dump_on(outputStream* s) { |
240 | s->print_cr("\t _num = %d, _sum = %7.3f, _sum_of_squares = %7.3f" , |
241 | _num, _sum, _sum_of_squares); |
242 | s->print_cr("\t _davg = %7.3f, _dvariance = %7.3f, _alpha = %7.3f" , |
243 | _davg, _dvariance, _alpha); |
244 | } |
245 | |
246 | void NumberSeq::dump_on(outputStream* s) { |
247 | AbsSeq::dump_on(s); |
248 | s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f" , _last, _maximum); |
249 | } |
250 | |
251 | void TruncatedSeq::dump_on(outputStream* s) { |
252 | AbsSeq::dump_on(s); |
253 | s->print_cr("\t\t _length = %d, _next = %d" , _length, _next); |
254 | for (int i = 0; i < _length; i++) { |
255 | if (i%5 == 0) { |
256 | s->cr(); |
257 | s->print("\t" ); |
258 | } |
259 | s->print("\t[%d]=%7.3f" , i, _sequence[i]); |
260 | } |
261 | s->cr(); |
262 | } |
263 | |