Boost logo

Boost-Commit :

From: john_at_[hidden]
Date: 2008-05-14 14:35:53


Author: johnmaddock
Date: 2008-05-14 14:35:52 EDT (Wed, 14 May 2008)
New Revision: 45357
URL: http://svn.boost.org/trac/boost/changeset/45357

Log:
Added float_advance + docs.
Changed pow<N> to reduce the number of template instantiations.
Text files modified:
   sandbox/math_toolkit/boost/math/special_functions/next.hpp | 61 ++++++++++++++++++++++++++++++++++++++++
   sandbox/math_toolkit/boost/math/special_functions/pow.hpp | 35 ++++++++++++++++------
   sandbox/math_toolkit/libs/math/doc/sf_and_dist/float_next.qbk | 25 ++++++++++++++++
   sandbox/math_toolkit/libs/math/test/test_next.cpp | 14 +++++++-
   4 files changed, 123 insertions(+), 12 deletions(-)

Modified: sandbox/math_toolkit/boost/math/special_functions/next.hpp
==============================================================================
--- sandbox/math_toolkit/boost/math/special_functions/next.hpp (original)
+++ sandbox/math_toolkit/boost/math/special_functions/next.hpp 2008-05-14 14:35:52 EDT (Wed, 14 May 2008)
@@ -241,6 +241,67 @@
    return boost::math::float_distance(a, b, policies::policy<>());
 }
 
+template <class T, class Policy>
+T float_advance(T val, int distance, const Policy& pol)
+{
+ //
+ // Error handling:
+ //
+ static const char* function = "float_advance<%1%>(%1%, int)";
+ if(!(boost::math::isfinite)(val))
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument val must be finite, but got %1%", val, pol);
+
+ if(val < 0)
+ return -float_advance(-val, -distance, pol);
+ if(distance == 0)
+ return val;
+ if(distance == 1)
+ return float_next(val, pol);
+ if(distance == -1)
+ return float_prior(val, pol);
+ BOOST_MATH_STD_USING
+ int expon;
+ frexp(val, &expon);
+ T limit = ldexp((distance < 0 ? T(0.5f) : T(1)), expon);
+ if(val <= tools::min_value<T>())
+ {
+ limit = sign(T(distance)) * tools::min_value<T>();
+ }
+ T limit_distance = float_distance(val, limit);
+ while(fabs(limit_distance) < abs(distance))
+ {
+ distance -= itrunc(limit_distance);
+ val = limit;
+ if(distance < 0)
+ {
+ limit /= 2;
+ expon--;
+ }
+ else
+ {
+ limit *= 2;
+ expon++;
+ }
+ limit_distance = float_distance(val, limit);
+ }
+ if((0.5f == frexp(val, &expon)) && (distance < 0))
+ --expon;
+ T diff = 0;
+ if(val != 0)
+ diff = distance * ldexp(T(1), expon - tools::digits<T>());
+ if(diff == 0)
+ diff = distance * detail::get_smallest_value<T>();
+ return val += diff;
+}
+
+template <class T>
+inline T float_advance(const T& val, int distance)
+{
+ return boost::math::float_advance(val, distance, policies::policy<>());
+}
+
 }} // namespaces
 
 #endif // BOOST_MATH_SPECIAL_NEXT_HPP

Modified: sandbox/math_toolkit/boost/math/special_functions/pow.hpp
==============================================================================
--- sandbox/math_toolkit/boost/math/special_functions/pow.hpp (original)
+++ sandbox/math_toolkit/boost/math/special_functions/pow.hpp 2008-05-14 14:35:52 EDT (Wed, 14 May 2008)
@@ -26,11 +26,11 @@
 namespace detail {
 
 
-template <int N>
+template <int N, bool odd>
 struct positive_power;
 
 template <>
-struct positive_power<0>
+struct positive_power<0, false>
 {
     template <typename T>
     static typename tools::promote_args<T>::type result(T)
@@ -38,33 +38,48 @@
 };
 
 template <>
-struct positive_power<2>
+struct positive_power<1, false>
+{
+ template <typename T>
+ static typename tools::promote_args<T>::type result(T x)
+ { return x; }
+};
+
+template <>
+struct positive_power<2, false>
 {
     template <typename T>
     static typename tools::promote_args<T>::type result(T base)
     { return base*base; }
 };
 
-template <int N>
+template <int N, bool odd>
 struct positive_power
 {
     template <typename T>
     static typename tools::promote_args<T>::type result(T base)
     {
- return (N%2) ? base*positive_power<N-1>::result(base)
- : positive_power<2>::result(
- positive_power<N/2>::result(base)
- );
+ return base*positive_power<N-1, (N-1)%2>::result(base);
     }
 };
 
+template <int N>
+struct positive_power<N, false>
+{
+ template <typename T>
+ static typename tools::promote_args<T>::type result(T base)
+ {
+ return positive_power<2, false>::result(
+ positive_power<N/2, (N/2)%2>::result(base));
+ }
+};
 
 template <int N, bool>
 struct power_if_positive
 {
     template <typename T, class Policy>
     static typename tools::promote_args<T>::type result(T base, const Policy&)
- { return positive_power<N>::result(base); }
+ { return positive_power<N, N%2>::result(base); }
 };
 
 template <int N>
@@ -83,7 +98,7 @@
                    );
         }
 
- return T(1) / positive_power<-N>::result(base);
+ return T(1) / positive_power<-N, (-N)%2>::result(base);
     }
 };
 

Modified: sandbox/math_toolkit/libs/math/doc/sf_and_dist/float_next.qbk
==============================================================================
--- sandbox/math_toolkit/libs/math/doc/sf_and_dist/float_next.qbk (original)
+++ sandbox/math_toolkit/libs/math/doc/sf_and_dist/float_next.qbk 2008-05-14 14:35:52 EDT (Wed, 14 May 2008)
@@ -162,6 +162,31 @@
 [endsect] [/section:float_distance Calculating the Representation Distance
    Between Two Floating Point Values (ULP) float_distance]
 
+[section:float_advance Advancing a Floating Point Value by a Specific
+Representation Distance (ULP) float_advance]
+
+Function float_advance advances a floating point number by a specified number
+of ULP.
+
+[h4 Synopsis]
+
+``
+#include <boost/math/special_functions/next.hpp>
+``
+
+ namespace boost{ namespace math{
+
+ template <class FPT>
+ FPT float_advance(FPT val, int distance);
+
+ }} // namespaces
+
+[h4 Description - float_advance]
+
+Returns a floating point number /r/ such that `float_distance(val, r) == distance`.
+
+[endsect] [/section:float_advance]
+
 [endsect] [/ section:next_float Floating-Point Representation Distance (ULP),
    and Finding Adjacent Floating-Point Values]
 

Modified: sandbox/math_toolkit/libs/math/test/test_next.cpp
==============================================================================
--- sandbox/math_toolkit/libs/math/test/test_next.cpp (original)
+++ sandbox/math_toolkit/libs/math/test/test_next.cpp 2008-05-14 14:35:52 EDT (Wed, 14 May 2008)
@@ -36,6 +36,11 @@
    BOOST_CHECK_EQUAL(float_distance(float_next(float_prior(val)), val), 0);
    BOOST_CHECK_EQUAL(float_prior(float_next(val)), val);
    BOOST_CHECK_EQUAL(float_next(float_prior(val)), val);
+
+ BOOST_CHECK_EQUAL(float_distance(float_advance(val, 4), val), -4);
+ BOOST_CHECK_EQUAL(float_distance(float_advance(val, -4), val), 4);
+ BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4);
+ BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4);
 }
 
 template <class T>
@@ -55,8 +60,11 @@
    test_value(-boost::math::tools::epsilon<T>(), name);
    test_value(boost::math::tools::min_value<T>(), name);
    test_value(-boost::math::tools::min_value<T>(), name);
- test_value(z, name);
- test_value(-z, name);
+ if(std::numeric_limits<T>::is_specialized)
+ {
+ test_value(z, name);
+ test_value(-z, name);
+ }
    test_value(one, name);
    test_value(-one, name);
    test_value(two, name);
@@ -92,6 +100,8 @@
       }
       BOOST_CHECK_EQUAL(boost::math::float_distance(v1, val), -primes[i]);
       BOOST_CHECK_EQUAL(boost::math::float_distance(v2, val), primes[i]);
+ BOOST_CHECK_EQUAL(boost::math::float_advance(val, primes[i]), v1);
+ BOOST_CHECK_EQUAL(boost::math::float_advance(val, -primes[i]), v2);
    }
 }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk