diff options
author | Ossama Othman <ossama-othman@users.noreply.github.com> | 2007-03-06 23:07:04 +0000 |
---|---|---|
committer | Ossama Othman <ossama-othman@users.noreply.github.com> | 2007-03-06 23:07:04 +0000 |
commit | 8f64e37aaed7bce875157f711f71b6b28e3fbad4 (patch) | |
tree | 45547ab4d3daa28e629b94e9ca301ff72a816959 | |
parent | a66e2e62769504b69de2971866863c4071365a8b (diff) | |
download | ATCD-8f64e37aaed7bce875157f711f71b6b28e3fbad4.tar.gz |
ChangeLogTag:Tue Mar 6 23:06:15 UTC 2007 Ossama Othman <ossama_othman at symantec dot com>
-rw-r--r-- | ACE/ChangeLog | 13 | ||||
-rw-r--r-- | ACE/ace/Time_Value.cpp | 52 |
2 files changed, 50 insertions, 15 deletions
diff --git a/ACE/ChangeLog b/ACE/ChangeLog index 7fe9f32d6d2..fa5ee5cefe2 100644 --- a/ACE/ChangeLog +++ b/ACE/ChangeLog @@ -1,3 +1,16 @@ +Tue Mar 6 23:06:15 UTC 2007 Ossama Othman <ossama_othman at symantec dot com> + + * ace/Time_Value.cpp (operator*=): + + Use long double for internal computations if double is not large + enough to retain precision of the time_t/suseconds_t values. + This will only provide improved behavior with compilers that + support double-extended precision floating numbers, i.e. >= 79 + bits. + + Added comments to explain what is being done in the + implementation. + Tue Mar 6 07:47:12 UTC 2007 Johnny Willemsen <jwillemsen@remedy.nl> * ace/OS.inl: diff --git a/ACE/ace/Time_Value.cpp b/ACE/ace/Time_Value.cpp index bc8f6218159..97a6bd8c492 100644 --- a/ACE/ace/Time_Value.cpp +++ b/ACE/ace/Time_Value.cpp @@ -10,6 +10,7 @@ ACE_RCSID (ace, #endif /* __ACE_INLINE__ */ #include "ace/Numeric_Limits.h" +#include "ace/If_Then_Else.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL @@ -213,31 +214,52 @@ ACE_Time_Value::normalize (void) ACE_Time_Value & ACE_Time_Value::operator *= (double d) { - // double is long enough (16 digits) to not lose the accuracy. - double time_total = + // The floating type to be used in the computations. It should be + // large enough to hold a time_t. We actually want a floating type + // with enough digits in its mantissa to hold a time_t without + // losing precision. For example, if FLT_RADIX is 2 and + // LDBL_MANT_DIG is 64, a long double has a 64 bit wide mantissa, + // which would be sufficient to hold a 64 bit time_t value without + // losing precision. + // + // For now we'll simply go with long double if it is larger than + // time_t. We're hosed if long double isn't large enough. + typedef ACE::If_Then_Else<(sizeof (double) > sizeof (time_t)), + double, + long double>::result_type float_type; + + // long double is generally long enough to not lose precision. + float_type time_total = (this->sec () - + static_cast<double> (this->usec ()) / ACE_ONE_SECOND_IN_USECS) * d; + + static_cast<float_type> (this->usec ()) / ACE_ONE_SECOND_IN_USECS) * d; - // shall we saturate the result? - static const double max_int = ACE_Numeric_Limits<time_t>::max () + 0.999999; - static const double min_int = ACE_Numeric_Limits<time_t>::min () - 0.999999; + // Shall we saturate the result? + float_type const max_time = + ACE_Numeric_Limits<time_t>::max () + static_cast<float_type> (0.999999); + float_type const min_time = + ACE_Numeric_Limits<time_t>::min () - static_cast<float_type> (0.999999); - if (time_total > max_int) - time_total = max_int; - if (time_total < min_int) - time_total = min_int; + // Truncate if necessary. + if (time_total > max_time) + time_total = max_time; + else if (time_total < min_time) + time_total = min_time; - const time_t time_sec = static_cast<time_t> (time_total); + // Retrieve non-fractional portion of seconds. + time_t const time_sec = static_cast<time_t> (time_total); - time_total -= time_sec; - time_total *= ACE_ONE_SECOND_IN_USECS; + time_total -= time_sec; // Retrieve the fraction of seconds. + time_total *= ACE_ONE_SECOND_IN_USECS; // Convert to microseconds. suseconds_t time_usec = static_cast<suseconds_t> (time_total); + float_type const usec_diff = time_total - time_usec; + static float_type const roundup_threshold = 0.5; // Always 0.5. + // round up the result to save the last usec - if (time_usec > 0 && (time_total - time_usec) >= 0.5) + if (time_usec > 0 && usec_diff >= roundup_threshold) ++time_usec; - else if (time_usec < 0 && (time_total - time_usec) <= -0.5) + else if (time_usec < 0 && usec_diff <= -roundup_threshold) --time_usec; this->set (time_sec, time_usec); |