Stats.cpp

Go to the documentation of this file.
00001 // $Id: Stats.cpp 80826 2008-03-04 14:51:23Z wotte $
00002 
00003 #include "ace/Stats.h"
00004 
00005 #if !defined (__ACE_INLINE__)
00006 # include "ace/Stats.inl"
00007 #endif /* __ACE_INLINE__ */
00008 
00009 #include "ace/OS_NS_stdio.h"
00010 #include "ace/OS_NS_string.h"
00011 
00012 ACE_RCSID(ace, Stats, "$Id: Stats.cpp 80826 2008-03-04 14:51:23Z wotte $")
00013 
00014 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00015 
00016 ACE_UINT32
00017 ACE_Stats_Value::fractional_field (void) const
00018 {
00019   if (precision () == 0)
00020     {
00021       return 1;
00022     }
00023   else
00024     {
00025       ACE_UINT32 field = 10;
00026       for (u_int i = 0; i < precision () - 1; ++i)
00027         {
00028           field *= 10;
00029         }
00030 
00031       return field;
00032     }
00033 }
00034 
00035 int
00036 ACE_Stats::sample (const ACE_INT32 value)
00037 {
00038   if (samples_.enqueue_tail (value) == 0)
00039     {
00040       ++number_of_samples_;
00041       if (number_of_samples_ == 0)
00042         {
00043           // That's a lot of samples :-)
00044           overflow_ = EFAULT;
00045           return -1;
00046         }
00047 
00048       if (value < min_)
00049         min_ = value;
00050 
00051       if (value > max_)
00052         max_ = value;
00053 
00054       return 0;
00055     }
00056   else
00057     {
00058       // Probably failed due to running out of memory when trying to
00059       // enqueue the new value.
00060       overflow_ = errno;
00061       return -1;
00062     }
00063 }
00064 
00065 void
00066 ACE_Stats::mean (ACE_Stats_Value &m,
00067                  const ACE_UINT32 scale_factor)
00068 {
00069   if (number_of_samples_ > 0)
00070     {
00071 #if defined ACE_LACKS_LONGLONG_T
00072       // If ACE_LACKS_LONGLONG_T, then ACE_UINT64 is a user-defined class.
00073       // To prevent having to construct a static of that class, declare it
00074       // on the stack, and construct it, in each function that needs it.
00075       const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8);
00076 #else  /* ! ACE_LACKS_LONGLONG_T */
00077       const ACE_UINT64 ACE_STATS_INTERNAL_OFFSET =
00078         ACE_UINT64_LITERAL (0x100000000);
00079 #endif /* ! ACE_LACKS_LONGLONG_T */
00080 
00081       ACE_UINT64 sum = ACE_STATS_INTERNAL_OFFSET;
00082       ACE_Unbounded_Queue_Iterator<ACE_INT32> i (samples_);
00083       while (! i.done ())
00084         {
00085           ACE_INT32 *sample;
00086           if (i.next (sample))
00087             {
00088               sum += *sample;
00089               i.advance ();
00090             }
00091         }
00092 
00093       // sum_ was initialized with ACE_STATS_INTERNAL_OFFSET, so
00094       // subtract that off here.
00095       quotient (sum - ACE_STATS_INTERNAL_OFFSET,
00096                 number_of_samples_ * scale_factor,
00097                 m);
00098     }
00099   else
00100     {
00101       m.whole (0);
00102       m.fractional (0);
00103     }
00104 }
00105 
00106 int
00107 ACE_Stats::std_dev (ACE_Stats_Value &std_dev,
00108                     const ACE_UINT32 scale_factor)
00109 {
00110   if (number_of_samples_ <= 1)
00111     {
00112       std_dev.whole (0);
00113       std_dev.fractional (0);
00114     }
00115   else
00116     {
00117       const ACE_UINT32 field = std_dev.fractional_field ();
00118 
00119       // The sample standard deviation is:
00120       //
00121       // sqrt (sum (sample_i - mean)^2 / (number_of_samples_ - 1))
00122 
00123       ACE_UINT64 mean_scaled;
00124       // Calculate the mean, scaled, so that we don't lose its
00125       // precision.
00126       ACE_Stats_Value avg (std_dev.precision ());
00127       mean (avg, 1u);
00128       avg.scaled_value (mean_scaled);
00129 
00130       // Calculate the summation term, of squared differences from the
00131       // mean.
00132       ACE_UINT64 sum_of_squares = 0;
00133       ACE_Unbounded_Queue_Iterator<ACE_INT32> i (samples_);
00134       while (! i.done ())
00135         {
00136           ACE_INT32 *sample;
00137           if (i.next (sample))
00138             {
00139               const ACE_UINT64 original_sum_of_squares = sum_of_squares;
00140 
00141               // Scale up by field width so that we don't lose the
00142               // precision of the mean.  Carefully . . .
00143               const ACE_UINT64 product (*sample * field);
00144 
00145               ACE_UINT64 difference;
00146               // NOTE: please do not reformat this code!  It //
00147               // works with the Diab compiler the way it is! //
00148               if  (product >= mean_scaled)                   //
00149                 {                                            //
00150                   difference = product - mean_scaled;        //
00151                 }                                            //
00152               else                                           //
00153                 {                                            //
00154                   difference = mean_scaled - product;        //
00155                 }                                            //
00156               // NOTE: please do not reformat this code!  It //
00157               // works with the Diab compiler the way it is! //
00158 
00159               // Square using 64-bit arithmetic.
00160               sum_of_squares += difference * ACE_U64_TO_U32 (difference);
00161               i.advance ();
00162 
00163               if (sum_of_squares < original_sum_of_squares)
00164                 {
00165                   overflow_ = ENOSPC;
00166                   return -1;
00167                 }
00168             }
00169         }
00170 
00171       // Divide the summation by (number_of_samples_ - 1), to get the
00172       // variance.  In addition, scale the variance down to undo the
00173       // mean scaling above.  Otherwise, it can get too big.
00174       ACE_Stats_Value variance (std_dev.precision ());
00175       quotient (sum_of_squares,
00176                 (number_of_samples_ - 1) * field * field,
00177                 variance);
00178 
00179       // Take the square root of the variance to get the standard
00180       // deviation.  First, scale up . . .
00181       ACE_UINT64 scaled_variance;
00182       variance.scaled_value (scaled_variance);
00183 
00184       // And scale up, once more, because we'll be taking the square
00185       // root.
00186       scaled_variance *= field;
00187       ACE_Stats_Value unscaled_standard_deviation (std_dev.precision ());
00188       square_root (scaled_variance,
00189                    unscaled_standard_deviation);
00190 
00191       // Unscale.
00192       quotient (unscaled_standard_deviation,
00193                 scale_factor * field,
00194                 std_dev);
00195     }
00196 
00197   return 0;
00198 }
00199 
00200 
00201 void
00202 ACE_Stats::reset (void)
00203 {
00204   overflow_ = 0u;
00205   number_of_samples_ = 0u;
00206   min_ = 0x7FFFFFFF;
00207   max_ = -0x8000 * 0x10000;
00208   samples_.reset ();
00209 }
00210 
00211 int
00212 ACE_Stats::print_summary (const u_int precision,
00213                           const ACE_UINT32 scale_factor,
00214                           FILE *file) const
00215 {
00216   ACE_TCHAR mean_string [128];
00217   ACE_TCHAR std_dev_string [128];
00218   ACE_TCHAR min_string [128];
00219   ACE_TCHAR max_string [128];
00220   int success = 0;
00221 
00222   for (int tmp_precision = precision;
00223        ! overflow_  &&  ! success  &&  tmp_precision >= 0;
00224        --tmp_precision)
00225     {
00226       // Build a format string, in case the C library doesn't support %*u.
00227       ACE_TCHAR format[32];
00228       if (tmp_precision == 0)
00229         ACE_OS::sprintf (format, ACE_TEXT ("%%%d"), tmp_precision);
00230       else
00231         ACE_OS::sprintf (format, ACE_TEXT ("%%d.%%0%du"), tmp_precision);
00232 
00233       ACE_Stats_Value u (tmp_precision);
00234       ((ACE_Stats *) this)->mean (u, scale_factor);
00235       ACE_OS::sprintf (mean_string, format, u.whole (), u.fractional ());
00236 
00237       ACE_Stats_Value sd (tmp_precision);
00238       if (((ACE_Stats *) this)->std_dev (sd, scale_factor))
00239         {
00240           success = 0;
00241           continue;
00242         }
00243       else
00244         {
00245           success = 1;
00246         }
00247       ACE_OS::sprintf (std_dev_string, format, sd.whole (), sd.fractional ());
00248 
00249       ACE_Stats_Value minimum (tmp_precision), maximum (tmp_precision);
00250       if (min_ != 0)
00251         {
00252           const ACE_UINT64 m (min_);
00253           quotient (m, scale_factor, minimum);
00254         }
00255       if (max_ != 0)
00256         {
00257           const ACE_UINT64 m (max_);
00258           quotient (m, scale_factor, maximum);
00259         }
00260       ACE_OS::sprintf (min_string, format,
00261                        minimum.whole (), minimum.fractional ());
00262       ACE_OS::sprintf (max_string, format,
00263                        maximum.whole (), maximum.fractional ());
00264     }
00265 
00266   if (success == 1)
00267     {
00268       ACE_OS::fprintf (file, ACE_TEXT ("samples: %u (%s - %s); mean: ")
00269                        ACE_TEXT ("%s; std dev: %s\n"),
00270                        samples (), min_string, max_string,
00271                        mean_string, std_dev_string);
00272       return 0;
00273     }
00274   else
00275     {
00276 #if !defined (ACE_HAS_WINCE)
00277       ACE_OS::fprintf (file,
00278                        ACE_TEXT ("ACE_Stats::print_summary: OVERFLOW: %s\n"),
00279                        ACE_OS::strerror (overflow_));
00280 #else
00281       // WinCE doesn't have strerror ;(
00282       ACE_OS::fprintf (file,
00283                        ACE_TEXT ("ACE_Stats::print_summary: OVERFLOW\n"));
00284 #endif /* ACE_HAS_WINCE */
00285       return -1;
00286     }
00287 }
00288 
00289 void
00290 ACE_Stats::quotient (const ACE_UINT64 dividend,
00291                      const ACE_UINT32 divisor,
00292                      ACE_Stats_Value &quotient)
00293 {
00294   // The whole part of the division comes from simple integer division.
00295   quotient.whole (static_cast<ACE_UINT32> (divisor == 0
00296                                            ?  0  :  dividend / divisor));
00297 
00298   if (quotient.precision () > 0  ||  divisor == 0)
00299     {
00300       const ACE_UINT32 field = quotient.fractional_field ();
00301 
00302       // Fractional = (dividend % divisor) * 10^precision / divisor
00303 
00304       // It would be nice to add round-up term:
00305       // Fractional = (dividend % divisor) * 10^precision / divisor  +
00306       //                10^precision/2 / 10^precision
00307       //            = ((dividend % divisor) * 10^precision  +  divisor) /
00308       //                divisor
00309       quotient.fractional (static_cast<ACE_UINT32> (
00310                              dividend % divisor * field / divisor));
00311     }
00312   else
00313     {
00314       // No fractional portion is requested, so don't bother
00315       // calculating it.
00316       quotient.fractional (0);
00317     }
00318 }
00319 
00320 void
00321 ACE_Stats::quotient (const ACE_Stats_Value &dividend,
00322                      const ACE_UINT32 divisor,
00323                      ACE_Stats_Value &quotient)
00324 {
00325   // The whole part of the division comes from simple integer division.
00326   quotient.whole (divisor == 0  ?  0  :  dividend.whole () / divisor);
00327 
00328   if (quotient.precision () > 0  ||  divisor == 0)
00329     {
00330       const ACE_UINT32 field = quotient.fractional_field ();
00331 
00332       // Fractional = (dividend % divisor) * 10^precision / divisor.
00333       quotient.fractional (dividend.whole () % divisor * field / divisor  +
00334                            dividend.fractional () / divisor);
00335     }
00336   else
00337     {
00338       // No fractional portion is requested, so don't bother
00339       // calculating it.
00340       quotient.fractional (0);
00341     }
00342 }
00343 
00344 void
00345 ACE_Stats::square_root (const ACE_UINT64 n,
00346                         ACE_Stats_Value &square_root)
00347 {
00348   ACE_UINT32 floor = 0;
00349   ACE_UINT32 ceiling = 0xFFFFFFFFu;
00350   ACE_UINT32 mid = 0;
00351   u_int i;
00352 
00353   // The maximum number of iterations is log_2 (2^64) == 64.
00354   for (i = 0; i < 64; ++i)
00355     {
00356       mid = (ceiling - floor) / 2  +  floor;
00357       if (floor == mid)
00358         // Can't divide the interval any further.
00359         break;
00360       else
00361         {
00362           // Multiply carefully to avoid overflow.
00363           ACE_UINT64 mid_squared = mid; mid_squared *= mid;
00364           if (mid_squared == n)
00365             break;
00366           else if (mid_squared < n)
00367             floor = mid;
00368           else
00369             ceiling = mid;
00370         }
00371     }
00372 
00373   square_root.whole (mid);
00374   ACE_UINT64 mid_squared = mid; mid_squared *= mid;
00375 
00376   if (square_root.precision ()  &&  mid_squared < n)
00377     {
00378       // (mid * 10^precision + fractional)^2 ==
00379       //   n^2 * 10^(precision * 2)
00380 
00381       const ACE_UINT32 field = square_root.fractional_field ();
00382 
00383       floor = 0;
00384       ceiling = field;
00385       mid = 0;
00386 
00387       // Do the 64-bit arithmetic carefully to avoid overflow.
00388       ACE_UINT64 target = n;
00389       target *= field;
00390       target *= field;
00391 
00392       ACE_UINT64 difference = 0;
00393 
00394       for (i = 0; i < square_root.precision (); ++i)
00395         {
00396           mid = (ceiling - floor) / 2 + floor;
00397 
00398           ACE_UINT64 current = square_root.whole () * field  +  mid;
00399           current *= square_root.whole () * field  +  mid;
00400 
00401           if (floor == mid)
00402             {
00403               difference = target - current;
00404               break;
00405             }
00406           else if (current <= target)
00407             floor = mid;
00408           else
00409             ceiling = mid;
00410         }
00411 
00412       // Check to see if the fractional part should be one greater.
00413       ACE_UINT64 next = square_root.whole () * field  +  mid + 1;
00414       next *= square_root.whole () * field  +  mid + 1;
00415 
00416       square_root.fractional (next - target < difference  ?  mid + 1  :  mid);
00417     }
00418   else
00419     {
00420       // No fractional portion is requested, so don't bother
00421       // calculating it.
00422       square_root.fractional (0);
00423     }
00424 }
00425 
00426 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Tue Feb 2 17:18:43 2010 for ACE by  doxygen 1.4.7