lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master 569b775 2/2: Calculate integral powers more e


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 569b775 2/2: Calculate integral powers more efficiently
Date: Thu, 22 Dec 2016 02:13:10 +0000 (UTC)

branch: master
commit 569b775d3ffc4afc526a83cb1a769f6d604101a8
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Calculate integral powers more efficiently
    
    This appears to shift the balance away from using std::pow() and hoping
    to help it select a particular optimization for accuracy's sake, back
    toward an alternative implementation that is certain to be accurate and
    is now presumably about as efficient as it can be.
---
 round_to.hpp |   52 ++++++++++++++++++++++++++++++----------------------
 1 file changed, 30 insertions(+), 22 deletions(-)

diff --git a/round_to.hpp b/round_to.hpp
index ce1a0a3..733d73e 100644
--- a/round_to.hpp
+++ b/round_to.hpp
@@ -25,6 +25,7 @@
 #include "config.hpp"
 
 #include "mc_enum_type_enums.hpp"
+#include "stl_extensions.hpp"           // nonstd::power()
 
 #include <boost/static_assert.hpp>
 #include <boost/type_traits/is_float.hpp>
@@ -58,14 +59,31 @@ typedef long double max_prec_real;
 
 namespace detail
 {
-#if 0 // This elaborate workaround is probably no longer useful.
-// Returns 'r' raised to the 'n'th power. The sgi stl provides a faster
-// implementation as an extension (although it does not seem to work
-// with negative powers). Because this template function is called only
-// by the round_to constructor, efficiency here is not important in the
-// contemplated typical case where a round_to object is created once
-// and used to round many numbers. Defectively fails to check for
-// overflow or undeflow, but the round_to ctor does do that check.
+#if 1
+/// Raise 'r' to the integer power 'n'.
+///
+/// Motivation: To raise an integer-valued real to a positive integer
+/// power without any roundoff error as long as the result is exactly
+/// representable. See:
+///   http://lists.nongnu.org/archive/html/lmi/2016-12/msg00049.html
+///
+/// For negative 'n', the most accurate result possible is obtained by
+/// calculating power(r, -n), and returning its reciprocal calculated
+/// with the maximum available precision.
+///
+/// Because this template function is called only by the round_to
+/// constructor, efficiency here is not crucial in the contemplated
+/// typical case where a round_to object is created once and used to
+/// round many numbers, whereas it is crucial to avoid roundoff error.
+/// However, that does not justify gratuitous inefficiency, and the
+/// use of power() here means that the number of multiplications is
+/// O(log n), so this should be as fast as a library function that
+/// has been optimized for accuracy.
+///
+/// Fails to check for overflow or undeflow, but the round_to ctor
+/// does compare 'n' to the minimum and maximum decimal exponents,
+/// which suffices there because its 'r' is always ten.
+
 template<typename RealType>
 RealType perform_pow(RealType r, int n)
 {
@@ -75,25 +93,15 @@ RealType perform_pow(RealType r, int n)
         }
     if(n < 0)
         {
-        // Successive division by 'r' would lose precision at each step
-        // when 'r' is exactly representable but its reciprocal is not,
-        // and division is much slower than multiplication on some
-        // machines, so instead calculate the positive power and take
-        // its reciprocal.
-        return RealType(1.0) / perform_pow(r, -n);
+        return max_prec_real(1.0) / nonstd::power(r, -n);
         }
     else
         {
-        RealType z = r;
-        while(--n)
-            {
-            z *= r;
-            }
-        return z;
+        return nonstd::power(r, n);
         }
 }
 
-#else  // !0
+#else  // 0
 
 /// Raise an integer-valued real to an integer power.
 ///
@@ -129,7 +137,7 @@ RealType perform_pow(RealType r, int n)
         }
 }
 
-#endif // !0
+#endif // 0
 } // namespace detail
 
 inline rounding_style& default_rounding_style()



reply via email to

[Prev in Thread] Current Thread [Next in Thread]