diff options
author | levine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-05-20 20:50:30 +0000 |
---|---|---|
committer | levine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-05-20 20:50:30 +0000 |
commit | d016dbb25181e489ddf458bfa5870bb783b959fa (patch) | |
tree | 1620d9d701459cfb7db2c094c5390327b2fc5071 | |
parent | 2da649db7b790388a99231238ea6f5ba080bb99a (diff) | |
download | ATCD-d016dbb25181e489ddf458bfa5870bb783b959fa.tar.gz |
added ACE_Stats class
-rw-r--r-- | ace/Stats.cpp | 337 | ||||
-rw-r--r-- | ace/Stats.h | 172 | ||||
-rw-r--r-- | ace/Stats.i | 79 |
3 files changed, 588 insertions, 0 deletions
diff --git a/ace/Stats.cpp b/ace/Stats.cpp new file mode 100644 index 00000000000..b23c917d81c --- /dev/null +++ b/ace/Stats.cpp @@ -0,0 +1,337 @@ +// $Id$ + +#include "ace/Stats.h" + +#if !defined (__ACE_INLINE__) +# include "ace/Stats.i" +#endif /* __ACE_INLINE__ */ + +#if !defined ACE_LACKS_LONGLONG_T +// 1) If ACE_LACKS_LONGLONG_T, then ACE_UINT64 is a user-defined class. +// To prevent having to construct a static of that class, declare it +// on the stack, and construct it in, each function that needs it. +// 2) To avoid warnings from some compilers, split the 0x100000000ull +// constant into two pieces. +static const ACE_UINT64 ACE_STATS_INTERNAL_OFFSET = 0x10000ull * 0x10000ull; +#endif /* ! ACE_LACKS_LONGLONG_T */ + +ACE_UINT32 +ACE_Stats_Value::fractional_field (void) const +{ + ACE_UINT32 field = 10; + for (u_int i = 0; i < precision () - 1; ++i) + field *= 10; + + return field; +} + +int +ACE_Stats::sample (const ACE_INT32 value) +{ + if (overflow_) + { + // Had already overflowed. + return -1; + } + else + { + ++samples_; + if (samples_ == 0) + { + overflow_ = 1; + --samples_; + return -1; + } + else + { + ACE_UINT64 old_sum = sum_; + ACE_UINT64 old_sum_of_squares = sum_of_squares_; + + sum_ += value; + sum_of_squares_ += value * value; + + // Overflow checks. + if ((value >= 0 ? sum_ < old_sum : sum_ > old_sum) || + sum_of_squares_ < old_sum_of_squares) + { + overflow_ = 1; + --samples_; + sum_ = old_sum; + sum_of_squares_ = old_sum_of_squares; + return -1; + } + + if (value < min_) + min_ = value; + + if (value > max_) + max_ = value; + + return 0; + } + } +} + +void +ACE_Stats::mean (ACE_Stats_Value &mean, + const ACE_UINT32 scale_factor) const +{ + if (samples_ > 0) + { +#if defined ACE_LACKS_LONGLONG_T + const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8); +#endif /* ACE_LACKS_LONGLONG_T */ + + quotient (sum_ - ACE_STATS_INTERNAL_OFFSET, + samples_ * scale_factor, + mean); + } +} + +void +ACE_Stats::std_dev (ACE_Stats_Value &std_dev, + const ACE_UINT32 scale_factor) const +{ + if (samples_ <= 1) + { + std_dev.whole (0); + std_dev.fractional (0); + } + else + { +#if defined ACE_LACKS_LONGLONG_T + const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8); +#endif /* ACE_LACKS_LONGLONG_T */ + // The sample standard deviation is: + // + // sqrt ((sum_of_squares_ - sums^2/samples_) / (samples_-1)) + + // Calculate the square of sums divided by the number of samples, + // carefully putting it into a 64-bit integer. + const ACE_UINT64 sums_squared_over_samples = + (sum_ - ACE_STATS_INTERNAL_OFFSET) * + ((sum_ - ACE_STATS_INTERNAL_OFFSET) / samples_); + + // Divide the difference by (samples_ - 1), to get the variance. + // Don't scale the result, yet. + ACE_Stats_Value variance (std_dev.precision ()); + + quotient (sum_of_squares_ - sums_squared_over_samples, + samples_ - 1, + variance); + + const ACE_UINT32 field = std_dev.fractional_field (); + + // Take the square root of the variance to get the standard + // deviation. + ACE_UINT64 scaled_variance; + variance.scaled_value (scaled_variance); + // Scale up, once more, because we'll be taking the square root. + scaled_variance *= field; + ACE_Stats_Value unscaled_standard_deviation (std_dev.precision ()); + square_root (scaled_variance, + unscaled_standard_deviation); + + // Unscale. + quotient (unscaled_standard_deviation, + scale_factor * field, + std_dev); + } +} + + +void +ACE_Stats::reset (void) +{ +#if defined ACE_LACKS_LONGLONG_T + const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8); +#endif /* ACE_LACKS_LONGLONG_T */ + + overflow_ = 0u; + samples_ = 0u; + min_ = 0x7FFFFFFF; + max_ = -0x80000000; + sum_ = ACE_STATS_INTERNAL_OFFSET; + sum_of_squares_ = 0u; +} + +int +ACE_Stats::print_summary (const u_int precision, + const ACE_UINT32 scale_factor, + FILE *file) const +{ + if (overflow_) + ACE_OS::fprintf (file, + ASYS_TEXT ("ACE_Stats::print_summary: " + "there was overflow!\n")); + + // Build a format string, in case the C library doesn't support %*u. + char format[32]; + ACE_OS::sprintf (format, ASYS_TEXT ("%%d.%%0%du"), precision); + + ACE_Stats_Value u (precision); + mean (u, scale_factor); + char mean_string [128]; + ACE_OS::sprintf (mean_string, format, u.whole (), u.fractional ()); + + ACE_Stats_Value sd (precision); + std_dev (sd, scale_factor); + char std_dev_string [128]; + ACE_OS::sprintf (std_dev_string, format, sd.whole (), sd.fractional ()); + + ACE_Stats_Value minimum (precision), maximum (precision); + if (min_ != 0) + { + const ACE_UINT64 m (min_); + quotient (m, scale_factor, minimum); + } + if (max_ != 0) + { + const ACE_UINT64 m (max_); + quotient (m, scale_factor, maximum); + } + char min_string [128]; + char max_string [128]; + ACE_OS::sprintf (min_string, format, + minimum.whole (), minimum.fractional ()); + ACE_OS::sprintf (max_string, format, + maximum.whole (), maximum.fractional ()); + + ACE_OS::fprintf (file, ASYS_TEXT ("samples: %u (%s - %s); mean: " + "%s; std dev: %s\n"), + samples (), min_string, max_string, + mean_string, std_dev_string); + + return overflow_ ? -1 : 0; +} + +void +ACE_Stats::dump (void) const +{ + print_summary (3u); +} + +void +ACE_Stats::quotient (const ACE_UINT64 dividend, + const ACE_UINT32 divisor, + ACE_Stats_Value "ient) +{ + // The whole part of the division comes from simple integer division. + quotient.whole (divisor == 0 ? 0 : dividend / divisor); + + if (quotient.precision () > 0 || divisor == 0) + { + const ACE_UINT32 field = quotient.fractional_field (); + + // Fractional = (dividend % divisor) * 10^precision / divisor. + quotient.fractional (dividend % divisor * field / divisor); + } + else + // No fractional portion is requested, so don't bother + // calculating it. + quotient.fractional (0); +} + +void +ACE_Stats::quotient (const ACE_Stats_Value ÷nd, + const ACE_UINT32 divisor, + ACE_Stats_Value "ient) +{ + // The whole part of the division comes from simple integer division. + quotient.whole (divisor == 0 ? 0 : dividend.whole () / divisor); + + if (quotient.precision () > 0 || divisor == 0) + { + const ACE_UINT32 field = quotient.fractional_field (); + + // Fractional = (dividend % divisor) * 10^precision / divisor. + quotient.fractional (dividend.whole () % divisor * field / divisor + + dividend.fractional () / divisor); + } + else + // No fractional portion is requested, so don't bother + // calculating it. + quotient.fractional (0); +} + +void +ACE_Stats::square_root (const ACE_UINT64 n, + ACE_Stats_Value &square_root) +{ + ACE_UINT32 floor = 0; + ACE_UINT32 ceiling = 0xFFFFFFFFu; + ACE_UINT32 mid = 0; + u_int i; + + // The maximum number of iterations is log_2 (2^64) == 64. + for (i = 0; i < 64; ++i) + { + mid = (ceiling - floor) / 2 + floor; + if (floor == mid) + // Can't divide the interval any further. + break; + else + { + // Multiply carefully to avoid overflow. + ACE_UINT64 mid_squared = mid; mid_squared *= mid; + if (mid_squared == n) + break; + else if (mid_squared < n) + floor = mid; + else + ceiling = mid; + } + } + + square_root.whole (mid); + ACE_UINT64 mid_squared = mid; mid_squared *= mid; + + if (square_root.precision () && mid_squared < n) + { + // (mid * 10^precision + fractional)^2 == + // n^2 * 10^(precision * 2) + + const ACE_UINT32 field = square_root.fractional_field (); + + floor = 0; + ceiling = field; + mid = 0; + + // Do the 64-bit arithmetic carefully to avoid overflow. + ACE_UINT64 target = n; + target *= field; + target *= field; + + ACE_UINT64 difference = 0; + + for (i = 0; i < square_root.precision (); ++i) + { + mid = (ceiling - floor) / 2 + floor; + + ACE_UINT64 current = square_root.whole () * field + mid; + current *= square_root.whole () * field + mid; + + if (floor == mid) + { + difference = target - current; + break; + } + else if (current <= target) + floor = mid; + else + ceiling = mid; + } + + // Check to see if the fractional part should be one greater. + ACE_UINT64 next = square_root.whole () * field + mid + 1; + next *= square_root.whole () * field + mid + 1; + + square_root.fractional (next - target < difference ? mid + 1 : mid); + } + else + { + // No fractional portion is requested, so don't bother + // calculating it. + square_root.fractional (0); + } +} diff --git a/ace/Stats.h b/ace/Stats.h new file mode 100644 index 00000000000..599214fcebb --- /dev/null +++ b/ace/Stats.h @@ -0,0 +1,172 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// ace +// +// = FILENAME +// Stats.h +// +// = AUTHORS +// David L. Levine +// +// ============================================================================ + +#if !defined (ACE_STATS_H) +#define ACE_STATS_H + +#include "ace/ACE.h" + +class ACE_Export ACE_Stats_Value +{ + // = TITLE + // Helper class for ACE_Stats. + // + // = DESCRIPTION + // Container struct for 64-bit signed quantity and its + // precision. It would be nicer to use a fixed-point class, but + // this is sufficient. +public: + ACE_Stats_Value (const u_int precision); + // Constructor, which requires precision in terms of number of + // decimal digits. Don't use more than 9! + + u_int precision (void) const; + // Accessor for precision. + + void whole (const ACE_UINT32); + // Set the whole_ field. + + ACE_UINT32 whole (void) const; + // Accessor for the whole_ field. + + void fractional (const ACE_UINT32); + // Set the fractional_ field. + + ACE_UINT32 fractional (void) const; + // Accessor for the fractional_ field. + + ACE_UINT32 fractional_field (void) const; + // Calculates the maximum value of the fractional portion, given its + // precision. + + void scaled_value (ACE_UINT64 &) const; + // Access the value as an _unsigned_ 64 bit quantity. It scales the + // value up by <precision> decimal digits, so that no precision will + // be lost. It assumes that <whole_> is >= 0. + +private: + ACE_UINT32 whole_; + // The integer portion of the value. + + ACE_UINT32 fractional_; + // The fractional portion of the value. + + const u_int precision_; + // The number of decimal digits of precision represented by + // <fractional_>. + + ACE_UNIMPLEMENTED_FUNC (ACE_Stats_Value (void)) +}; + +class ACE_Export ACE_Stats +{ + // = TITLE + // Provides simple statistical analysis. + // + // = DESCRIPTION + // Simple statistical analysis package. Prominent features are: + // 1) It does not use any floating point arithmetic. + // 2) It handles positive and/or negative sample values. The + // sample value type is ACE_INT32. + // 3) It uses 64 bit unsigned, but not 64 bit signed, quantities + // internally. + // 4) It checks for overflow of internal state variables. + // 5) It has no static variables of other than built-in types. +public: + ACE_Stats (void); + // Default constructor. + + int sample (const ACE_INT32 value); + // Provide a new sample. Returns 0 on success, -1 if internal overflow. + // If internal overflow is reached on this or any previous call, the + // state is not changed. Therefore, print_summary () can still be used. + + ACE_UINT32 samples (void) const; + // Access the number of samples provided so far. + + ACE_INT32 min_value (void) const; + // Value of the minimum sample provided so far. + + ACE_INT32 max_value (void) const; + // Value of the maximum sample provided so far. + + void mean (ACE_Stats_Value &mean, + const ACE_UINT32 scale_factor = 1) const; + // Access the mean of all samples provided so far. The fractional + // part is to the specified number of digits. E.g., 3 fractional + // digits specifies that fractional part is in thousandths. + + void std_dev (ACE_Stats_Value &std_dev, + const ACE_UINT32 scale_factor = 1) const; + // Access the standard deviation, whole and fractional parts. See + // description of <mean> method for argument descriptions. + + int print_summary (const u_int precision, + const ACE_UINT32 scale_factor = 1, + FILE * = stdout) const; + // Print summary statistics. If scale_factor is not 1, then the + // results are divided by it, i.e., each of the samples is scaled + // down by it. Returns -1 if internal overflow had been reached. + // The statistics will still be valid, but only for the samples + // received prior to the overflow. + + void reset (); + // Initialize internal state. + + void dump (void) const; + // Print summary statictics to stdout. + + static void quotient (const ACE_UINT64 dividend, + const ACE_UINT32 divisor, + ACE_Stats_Value "ient); + // Utility division function, for ACE_UINT64 dividend. + + static void quotient (const ACE_Stats_Value ÷nd, + const ACE_UINT32 divisor, + ACE_Stats_Value "ient); + // Utility division function, for ACE_Stats_Value dividend. + + static void square_root (const ACE_UINT64 n, + ACE_Stats_Value &square_root); + // Sqrt function, which uses an oversimplified version of Newton's + // method. It's not fast, but it doesn't require floating point + // support. + +private: + u_int overflow_; + // Internal indication of whether there has been overflow. + + ACE_UINT32 samples_; + // Number of samples. + + ACE_INT32 min_; + // Minimum sample value. + + ACE_INT32 max_; + // Maximum sample value. + + ACE_UINT64 sum_; + // Running sum. + + ACE_UINT64 sum_of_squares_; + // Running sum of squares. +}; + +#if defined (__ACE_INLINE__) +#include "ace/Stats.i" +#endif /* __ACE_INLINE__ */ + +#endif /* ! ACE_STATS_H */ diff --git a/ace/Stats.i b/ace/Stats.i new file mode 100644 index 00000000000..73c2c743d05 --- /dev/null +++ b/ace/Stats.i @@ -0,0 +1,79 @@ +/* -*- C++ -*- */ +// $Id$ + +ACE_INLINE +ACE_Stats_Value::ACE_Stats_Value (const u_int precision) + : whole_ (0), + fractional_ (0), + precision_ (precision) +{ +} + +ACE_INLINE +u_int +ACE_Stats_Value::precision (void) const +{ + return precision_; +} + +ACE_INLINE +void +ACE_Stats_Value::whole (const ACE_UINT32 value) +{ + whole_ = value; +} + +ACE_INLINE +ACE_UINT32 +ACE_Stats_Value::whole (void) const +{ + return whole_; +} + +ACE_INLINE +void +ACE_Stats_Value::fractional (const ACE_UINT32 value) +{ + fractional_ = value; +} + +ACE_INLINE +ACE_UINT32 +ACE_Stats_Value::fractional (void) const +{ + return fractional_; +} + +ACE_INLINE +void +ACE_Stats_Value::scaled_value (ACE_UINT64 &sv) const +{ + sv = whole () * fractional_field () + fractional (); +} + +ACE_INLINE +ACE_Stats::ACE_Stats (void) +{ + reset (); +} + +ACE_INLINE +ACE_UINT32 +ACE_Stats::samples (void) const +{ + return samples_; +} + +ACE_INLINE +ACE_INT32 +ACE_Stats::min_value (void) const +{ + return min_; +} + +ACE_INLINE +ACE_INT32 +ACE_Stats::max_value (void) const +{ + return max_; +} |