Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / Stats.cpp
blob9af7cb4a35efecdebc4ab7d3bf1ebf78a96b0ba1
1 #include "ace/Stats.h"
3 #if !defined (__ACE_INLINE__)
4 # include "ace/Stats.inl"
5 #endif /* __ACE_INLINE__ */
7 #include "ace/OS_NS_stdio.h"
8 #include "ace/OS_NS_string.h"
10 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
12 ACE_UINT32
13 ACE_Stats_Value::fractional_field () const
15 if (precision () == 0)
17 return 1;
19 else
21 ACE_UINT32 field = 10;
22 for (u_int i = 0; i < precision () - 1; ++i)
24 field *= 10;
27 return field;
31 int
32 ACE_Stats::sample (const ACE_INT32 value)
34 if (samples_.enqueue_tail (value) == 0)
36 ++number_of_samples_;
37 if (number_of_samples_ == 0)
39 // That's a lot of samples :-)
40 overflow_ = EFAULT;
41 return -1;
44 if (value < min_)
45 min_ = value;
47 if (value > max_)
48 max_ = value;
50 return 0;
52 else
54 // Probably failed due to running out of memory when trying to
55 // enqueue the new value.
56 overflow_ = errno;
57 return -1;
61 void
62 ACE_Stats::mean (ACE_Stats_Value &m,
63 const ACE_UINT32 scale_factor)
65 if (number_of_samples_ > 0)
67 const ACE_UINT64 ACE_STATS_INTERNAL_OFFSET =
68 ACE_UINT64_LITERAL (0x100000000);
70 ACE_UINT64 sum = ACE_STATS_INTERNAL_OFFSET;
71 ACE_Unbounded_Queue_Iterator<ACE_INT32> i (samples_);
72 while (! i.done ())
74 ACE_INT32 *sample;
75 if (i.next (sample))
77 sum += *sample;
78 i.advance ();
82 // sum_ was initialized with ACE_STATS_INTERNAL_OFFSET, so
83 // subtract that off here.
84 quotient (sum - ACE_STATS_INTERNAL_OFFSET,
85 number_of_samples_ * scale_factor,
86 m);
88 else
90 m.whole (0);
91 m.fractional (0);
95 int
96 ACE_Stats::std_dev (ACE_Stats_Value &std_dev,
97 const ACE_UINT32 scale_factor)
99 if (number_of_samples_ <= 1)
101 std_dev.whole (0);
102 std_dev.fractional (0);
104 else
106 const ACE_UINT32 field = std_dev.fractional_field ();
108 // The sample standard deviation is:
110 // sqrt (sum (sample_i - mean)^2 / (number_of_samples_ - 1))
112 ACE_UINT64 mean_scaled;
113 // Calculate the mean, scaled, so that we don't lose its
114 // precision.
115 ACE_Stats_Value avg (std_dev.precision ());
116 mean (avg, 1u);
117 avg.scaled_value (mean_scaled);
119 // Calculate the summation term, of squared differences from the
120 // mean.
121 ACE_UINT64 sum_of_squares = 0;
122 ACE_Unbounded_Queue_Iterator<ACE_INT32> i (samples_);
123 while (! i.done ())
125 ACE_INT32 *sample;
126 if (i.next (sample))
128 const ACE_UINT64 original_sum_of_squares = sum_of_squares;
130 // Scale up by field width so that we don't lose the
131 // precision of the mean. Carefully . . .
132 const ACE_UINT64 product (*sample * field);
134 ACE_UINT64 difference;
135 // NOTE: please do not reformat this code! It //
136 // works with the Diab compiler the way it is! //
137 if (product >= mean_scaled) //
138 { //
139 difference = product - mean_scaled; //
140 } //
141 else //
142 { //
143 difference = mean_scaled - product; //
144 } //
145 // NOTE: please do not reformat this code! It //
146 // works with the Diab compiler the way it is! //
148 // Square using 64-bit arithmetic.
149 sum_of_squares += difference * ACE_U64_TO_U32 (difference);
150 i.advance ();
152 if (sum_of_squares < original_sum_of_squares)
154 overflow_ = ENOSPC;
155 return -1;
160 // Divide the summation by (number_of_samples_ - 1), to get the
161 // variance. In addition, scale the variance down to undo the
162 // mean scaling above. Otherwise, it can get too big.
163 ACE_Stats_Value variance (std_dev.precision ());
164 quotient (sum_of_squares,
165 (number_of_samples_ - 1) * field * field,
166 variance);
168 // Take the square root of the variance to get the standard
169 // deviation. First, scale up . . .
170 ACE_UINT64 scaled_variance;
171 variance.scaled_value (scaled_variance);
173 // And scale up, once more, because we'll be taking the square
174 // root.
175 scaled_variance *= field;
176 ACE_Stats_Value unscaled_standard_deviation (std_dev.precision ());
177 square_root (scaled_variance,
178 unscaled_standard_deviation);
180 // Unscale.
181 quotient (unscaled_standard_deviation,
182 scale_factor * field,
183 std_dev);
186 return 0;
190 void
191 ACE_Stats::reset ()
193 overflow_ = 0u;
194 number_of_samples_ = 0u;
195 min_ = 0x7FFFFFFF;
196 max_ = -0x8000 * 0x10000;
197 samples_.reset ();
201 ACE_Stats::print_summary (const u_int precision,
202 const ACE_UINT32 scale_factor,
203 FILE *file) const
205 ACE_TCHAR mean_string [128];
206 ACE_TCHAR std_dev_string [128];
207 ACE_TCHAR min_string [128];
208 ACE_TCHAR max_string [128];
209 int success = 0;
211 for (int tmp_precision = precision;
212 ! overflow_ && ! success && tmp_precision >= 0;
213 --tmp_precision)
215 // Build a format string, in case the C library doesn't support %*u.
216 ACE_TCHAR format[32];
217 if (tmp_precision == 0)
218 ACE_OS::snprintf (format, 32, ACE_TEXT ("%%%d"), tmp_precision);
219 else
220 ACE_OS::snprintf (format, 32, ACE_TEXT ("%%d.%%0%du"), tmp_precision);
222 ACE_Stats_Value u (tmp_precision);
223 ((ACE_Stats *) this)->mean (u, scale_factor);
224 ACE_OS::snprintf (mean_string, 128, format, u.whole (), u.fractional ());
226 ACE_Stats_Value sd (tmp_precision);
227 if (((ACE_Stats *) this)->std_dev (sd, scale_factor))
229 success = 0;
230 continue;
232 else
234 success = 1;
236 ACE_OS::snprintf (std_dev_string, 128, format, sd.whole (),
237 sd.fractional ());
239 ACE_Stats_Value minimum (tmp_precision), maximum (tmp_precision);
240 if (min_ != 0)
242 const ACE_UINT64 m (min_);
243 quotient (m, scale_factor, minimum);
245 if (max_ != 0)
247 const ACE_UINT64 m (max_);
248 quotient (m, scale_factor, maximum);
250 ACE_OS::snprintf (min_string, 128, format,
251 minimum.whole (), minimum.fractional ());
252 ACE_OS::snprintf (max_string, 128, format,
253 maximum.whole (), maximum.fractional ());
256 if (success == 1)
258 ACE_OS::fprintf (file, ACE_TEXT ("samples: %u (%s - %s); mean: ")
259 ACE_TEXT ("%s; std dev: %s\n"),
260 samples (), min_string, max_string,
261 mean_string, std_dev_string);
262 return 0;
264 else
266 ACE_OS::fprintf (file,
267 ACE_TEXT ("ACE_Stats::print_summary: OVERFLOW: %s\n"),
268 ACE_OS::strerror (overflow_));
270 return -1;
274 void
275 ACE_Stats::quotient (const ACE_UINT64 dividend,
276 const ACE_UINT32 divisor,
277 ACE_Stats_Value &quotient)
279 // The whole part of the division comes from simple integer division.
280 quotient.whole (static_cast<ACE_UINT32> (divisor == 0
281 ? 0 : dividend / divisor));
283 if (quotient.precision () > 0 || divisor == 0)
285 const ACE_UINT32 field = quotient.fractional_field ();
287 // Fractional = (dividend % divisor) * 10^precision / divisor
289 // It would be nice to add round-up term:
290 // Fractional = (dividend % divisor) * 10^precision / divisor +
291 // 10^precision/2 / 10^precision
292 // = ((dividend % divisor) * 10^precision + divisor) /
293 // divisor
294 quotient.fractional (static_cast<ACE_UINT32> (
295 dividend % divisor * field / divisor));
297 else
299 // No fractional portion is requested, so don't bother
300 // calculating it.
301 quotient.fractional (0);
305 void
306 ACE_Stats::quotient (const ACE_Stats_Value &dividend,
307 const ACE_UINT32 divisor,
308 ACE_Stats_Value &quotient)
310 // The whole part of the division comes from simple integer division.
311 quotient.whole (divisor == 0 ? 0 : dividend.whole () / divisor);
313 if (quotient.precision () > 0 || divisor == 0)
315 const ACE_UINT32 field = quotient.fractional_field ();
317 // Fractional = (dividend % divisor) * 10^precision / divisor.
318 quotient.fractional (dividend.whole () % divisor * field / divisor +
319 dividend.fractional () / divisor);
321 else
323 // No fractional portion is requested, so don't bother
324 // calculating it.
325 quotient.fractional (0);
329 void
330 ACE_Stats::square_root (const ACE_UINT64 n,
331 ACE_Stats_Value &square_root)
333 ACE_UINT32 floor = 0;
334 ACE_UINT32 ceiling = 0xFFFFFFFFu;
335 ACE_UINT32 mid = 0;
336 u_int i;
338 // The maximum number of iterations is log_2 (2^64) == 64.
339 for (i = 0; i < 64; ++i)
341 mid = (ceiling - floor) / 2 + floor;
342 if (floor == mid)
343 // Can't divide the interval any further.
344 break;
345 else
347 // Multiply carefully to avoid overflow.
348 ACE_UINT64 mid_squared = mid; mid_squared *= mid;
349 if (mid_squared == n)
350 break;
351 else if (mid_squared < n)
352 floor = mid;
353 else
354 ceiling = mid;
358 square_root.whole (mid);
359 ACE_UINT64 mid_squared = mid; mid_squared *= mid;
361 if (square_root.precision () && mid_squared < n)
363 // (mid * 10^precision + fractional)^2 ==
364 // n^2 * 10^(precision * 2)
366 const ACE_UINT32 field = square_root.fractional_field ();
368 floor = 0;
369 ceiling = field;
370 mid = 0;
372 // Do the 64-bit arithmetic carefully to avoid overflow.
373 ACE_UINT64 target = n;
374 target *= field;
375 target *= field;
377 ACE_UINT64 difference = 0;
379 for (i = 0; i < square_root.precision (); ++i)
381 mid = (ceiling - floor) / 2 + floor;
383 ACE_UINT64 current = square_root.whole () * field + mid;
384 current *= square_root.whole () * field + mid;
386 if (floor == mid)
388 difference = target - current;
389 break;
391 else if (current <= target)
392 floor = mid;
393 else
394 ceiling = mid;
397 // Check to see if the fractional part should be one greater.
398 ACE_UINT64 next = square_root.whole () * field + mid + 1;
399 next *= square_root.whole () * field + mid + 1;
401 square_root.fractional (next - target < difference ? mid + 1 : mid);
403 else
405 // No fractional portion is requested, so don't bother
406 // calculating it.
407 square_root.fractional (0);
411 ACE_END_VERSIONED_NAMESPACE_DECL