Boost logo

Boost-Commit :

From: john_at_[hidden]
Date: 2008-04-29 08:01:22


Author: johnmaddock
Date: 2008-04-29 08:01:22 EDT (Tue, 29 Apr 2008)
New Revision: 44878
URL: http://svn.boost.org/trac/boost/changeset/44878

Log:
Added first cut of nextafter family of functions.
Added:
   sandbox/math_toolkit/boost/math/special_functions/next.hpp (contents, props changed)
   sandbox/math_toolkit/libs/math/test/compile_test/sf_next_incl_test.cpp (contents, props changed)
   sandbox/math_toolkit/libs/math/test/test_next.cpp (contents, props changed)
Text files modified:
   sandbox/math_toolkit/boost/math/special_functions.hpp | 1 +
   sandbox/math_toolkit/boost/math/special_functions/math_fwd.hpp | 23 +++++++++++++++++++++++
   sandbox/math_toolkit/libs/math/test/Jamfile.v2 | 3 +++
   sandbox/math_toolkit/libs/math/test/compile_test/instantiate.hpp | 12 ++++++++++++
   4 files changed, 39 insertions(+), 0 deletions(-)

Modified: sandbox/math_toolkit/boost/math/special_functions.hpp
==============================================================================
--- sandbox/math_toolkit/boost/math/special_functions.hpp (original)
+++ sandbox/math_toolkit/boost/math/special_functions.hpp 2008-04-29 08:01:22 EDT (Tue, 29 Apr 2008)
@@ -41,6 +41,7 @@
 #include <boost/math/special_functions/legendre.hpp>
 #include <boost/math/special_functions/log1p.hpp>
 #include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/next.hpp>
 #include <boost/math/special_functions/powm1.hpp>
 #include <boost/math/special_functions/sign.hpp>
 #include <boost/math/special_functions/sin_pi.hpp>

Modified: sandbox/math_toolkit/boost/math/special_functions/math_fwd.hpp
==============================================================================
--- sandbox/math_toolkit/boost/math/special_functions/math_fwd.hpp (original)
+++ sandbox/math_toolkit/boost/math/special_functions/math_fwd.hpp 2008-04-29 08:01:22 EDT (Tue, 29 Apr 2008)
@@ -657,6 +657,24 @@
    template <class T>
    typename tools::promote_args<T>::type zeta(T s);
 
+ // next:
+ template <class T, class Policy>
+ T nextafter(const T&, const T&, const Policy&);
+ template <class T>
+ T nextafter(const T&, const T&);
+ template <class T, class Policy>
+ T next_greater(const T&, const Policy&);
+ template <class T>
+ T next_greater(const T&);
+ template <class T, class Policy>
+ T next_less(const T&, const Policy&);
+ template <class T>
+ T next_less(const T&);
+ template <class T, class Policy>
+ T edit_distance(const T&, const T&, const Policy&);
+ template <class T>
+ T edit_distance(const T&, const T&);
+
     } // namespace math
 } // namespace boost
 
@@ -1003,6 +1021,11 @@
    \
    template <int N, class T>\
    inline typename boost::math::tools::promote_args<T>::type pow(T v){ return boost::math::pow<N>(v, Policy()); }\
+ template <class T> T nextafter(const T& a, const T& b){ return boost::math::nextafter(a, b, Policy()); }\
+ template <class T> T next_greater(const T& a){ return boost::math::next_greater(a, Policy()); }\
+ template <class T> T next_less(const T& a){ return boost::math::next_less(a, Policy()); }\
+ template <class T> T edit_distance(const T& a, const T& b){ return boost::math::edit_distance(a, b, Policy()); }\
+
 
 #endif // BOOST_MATH_SPECIAL_MATH_FWD_HPP
 

Added: sandbox/math_toolkit/boost/math/special_functions/next.hpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/boost/math/special_functions/next.hpp 2008-04-29 08:01:22 EDT (Tue, 29 Apr 2008)
@@ -0,0 +1,240 @@
+// (C) Copyright John Maddock 2008.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SPECIAL_NEXT_HPP
+#define BOOST_MATH_SPECIAL_NEXT_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/math/special_functions/sign.hpp>
+
+#ifdef BOOST_MSVC
+#include <float.h>
+#endif
+
+namespace boost{ namespace math{
+
+namespace detail{
+
+template <class T>
+inline T get_smallest_value(mpl::true_ const&)
+{
+ return std::numeric_limits<T>::denorm_min();
+}
+
+template <class T>
+inline T get_smallest_value(mpl::false_ const&)
+{
+ return tools::min_value<T>();
+}
+
+template <class T>
+inline T get_smallest_value()
+{
+ return get_smallest_value<T>(mpl::bool_<std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::has_denorm>());
+}
+
+}
+
+template <class T, class Policy>
+T next_greater(const T& val, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ int expon;
+ static const char* function = "next_greater<%1%>(%1%)";
+
+ if(!(boost::math::isfinite)(val))
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument must be finite, but got %1%", val, pol);
+
+ if(val >= tools::max_value<T>())
+ return policies::raise_overflow_error<T>(function, 0, pol);
+
+ if(val == 0)
+ return detail::get_smallest_value<T>();
+
+ if(-0.5f == frexp(val, &expon))
+ --expon; // reduce exponent when val is a power of two, and negative.
+ T diff = ldexp(T(1), expon - tools::digits<T>());
+ if(diff == 0)
+ diff = detail::get_smallest_value<T>();
+ return val + diff;
+}
+
+#ifdef BOOST_MSVC
+template <class Policy>
+inline double next_greater(const double& val, const Policy& pol)
+{
+ static const char* function = "next_greater<%1%>(%1%)";
+
+ if(!(boost::math::isfinite)(val))
+ return policies::raise_domain_error<double>(
+ function,
+ "Argument must be finite, but got %1%", val, pol);
+
+ if(val >= tools::max_value<double>())
+ return policies::raise_overflow_error<double>(function, 0, pol);
+
+ return ::_nextafter(val, tools::max_value<double>());
+}
+#endif
+
+template <class T>
+inline T next_greater(const T& val)
+{
+ return next_greater(val, policies::policy<>());
+}
+
+template <class T, class Policy>
+T next_less(const T& val, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ int expon;
+ static const char* function = "next_less<%1%>(%1%)";
+
+ if(!(boost::math::isfinite)(val))
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument must be finite, but got %1%", val, pol);
+
+ if(val <= -tools::max_value<T>())
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+
+ if(val == 0)
+ return -detail::get_smallest_value<T>();
+
+ T remain = frexp(val, &expon);
+ if(remain == 0.5)
+ --expon; // when val is a power of two we must reduce the exponent
+ T diff = ldexp(T(1), expon - tools::digits<T>());
+ if(diff == 0)
+ diff = detail::get_smallest_value<T>();
+ return val - diff;
+}
+
+#ifdef BOOST_MSVC
+template <class Policy>
+inline double next_less(const double& val, const Policy& pol)
+{
+ static const char* function = "next_less<%1%>(%1%)";
+
+ if(!(boost::math::isfinite)(val))
+ return policies::raise_domain_error<double>(
+ function,
+ "Argument must be finite, but got %1%", val, pol);
+
+ if(val <= -tools::max_value<double>())
+ return -policies::raise_overflow_error<double>(function, 0, pol);
+
+ return ::_nextafter(val, -tools::max_value<double>());
+}
+#endif
+
+template <class T>
+inline T next_less(const T& val)
+{
+ return next_less(val, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline T nextafter(const T& val, const T& direction, const Policy& pol)
+{
+ return val < direction ? boost::math::next_greater(val, pol) : val == direction ? val : boost::math::next_less(val, pol);
+}
+
+template <class T>
+inline T nextafter(const T& val, const T& direction)
+{
+ return nextafter(val, direction, policies::policy<>());
+}
+
+template <class T, class Policy>
+T edit_distance(const T& a, const T& b, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ //
+ // Error handling:
+ //
+ static const char* function = "edit_distance<%1%>(%1%, %1%)";
+ if(!(boost::math::isfinite)(a))
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument a must be finite, but got %1%", a, pol);
+ if(!(boost::math::isfinite)(b))
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument b must be finite, but got %1%", b, pol);
+ //
+ // Special cases:
+ //
+ if(a == b)
+ return 0;
+ if(a == 0)
+ return 1 + edit_distance(boost::math::sign(b) * detail::get_smallest_value<T>(), b, pol);
+ if(b == 0)
+ return 1 + edit_distance(boost::math::sign(a) * detail::get_smallest_value<T>(), a, pol);
+ if(boost::math::sign(a) != boost::math::sign(b))
+ return 2 + edit_distance(boost::math::sign(b) * detail::get_smallest_value<T>(), b, pol)
+ + edit_distance(boost::math::sign(a) * detail::get_smallest_value<T>(), a, pol);
+
+ if((std::min)(fabs(a), fabs(b)) / (std::max)(fabs(a), fabs(b)) < 2 * tools::epsilon<T>())
+ {
+ bool biga = fabs(a) > fabs(b);
+ T split = ldexp(biga ? b : a, tools::digits<T>() - 2);
+ return edit_distance(a, split, pol) + edit_distance(split, b, pol);
+ }
+
+ BOOST_MATH_STD_USING
+ int expon;
+ //
+ // We're going to left shift the result by the exponent of the
+ // smaller of the two values (irrespective of sign):
+ //
+ T mv = (std::min)(fabs(a), fabs(b));
+ //
+ // Note that if mv is a denorm then the usual formula fails
+ // because we actually have fewer than tools::digits<T>()
+ // significant bits in the representation:
+ //
+ frexp((boost::math::fpclassify(mv) == FP_SUBNORMAL) ? tools::min_value<T>() : mv, &expon);
+ expon = tools::digits<T>() - expon;
+ //
+ // Use compensated double-double addition to avoid rounding
+ // errors in the subtraction, note this will still fail if
+ // the two values differ by many orders of magnitute:
+ //
+ T mb = -b;
+ T x = a + mb;
+ T z = x - a;
+ T y = (a - (x - z)) + (mb - z);
+ if(x < 0)
+ {
+ x = -x;
+ y = -y;
+ }
+
+ T result = ldexp(x, expon) + ldexp(y, expon);
+ //
+ // Result must be an integer:
+ //
+ BOOST_ASSERT(result == floor(result));
+ return result;
+}
+
+template <class T>
+T edit_distance(const T& a, const T& b)
+{
+ return boost::math::edit_distance(a, b, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_SPECIAL_NEXT_HPP
+

Modified: sandbox/math_toolkit/libs/math/test/Jamfile.v2
==============================================================================
--- sandbox/math_toolkit/libs/math/test/Jamfile.v2 (original)
+++ sandbox/math_toolkit/libs/math/test/Jamfile.v2 2008-04-29 08:01:22 EDT (Tue, 29 Apr 2008)
@@ -246,6 +246,7 @@
         : # requirements
               <define>TEST_REAL_CONCEPT
         : test_negative_binomial_real_concept ;
+run test_next.cpp ;
 run test_nc_chi_squared.cpp
         : # command line
         : # input files
@@ -444,6 +445,7 @@
 compile compile_test/sf_log1p_incl_test.cpp ;
 compile compile_test/sf_math_fwd_incl_test.cpp ;
 compile compile_test/sf_modf_incl_test.cpp ;
+compile compile_test/sf_next_incl_test.cpp ;
 compile compile_test/sf_powm1_incl_test.cpp ;
 compile compile_test/sf_round_incl_test.cpp ;
 compile compile_test/sf_sign_incl_test.cpp ;
@@ -472,3 +474,4 @@
 compile compile_test/tools_test_inc_test.cpp ;
 compile compile_test/tools_toms748_inc_test.cpp ;
 
+

Modified: sandbox/math_toolkit/libs/math/test/compile_test/instantiate.hpp
==============================================================================
--- sandbox/math_toolkit/libs/math/test/compile_test/instantiate.hpp (original)
+++ sandbox/math_toolkit/libs/math/test/compile_test/instantiate.hpp 2008-04-29 08:01:22 EDT (Tue, 29 Apr 2008)
@@ -246,6 +246,10 @@
    boost::math::modf(v1, &ll);
 #endif
    boost::math::pow<2>(v1);
+ boost::math::nextafter(v1, v1);
+ boost::math::next_greater(v1);
+ boost::math::next_less(v1);
+ boost::math::edit_distance(v1, v1);
    //
    // All over again, with a policy this time:
    //
@@ -368,6 +372,10 @@
    modf(v1, &ll, pol);
 #endif
    boost::math::pow<2>(v1, pol);
+ boost::math::nextafter(v1, v1, pol);
+ boost::math::next_greater(v1, pol);
+ boost::math::next_less(v1, pol);
+ boost::math::edit_distance(v1, v1, pol);
    //
    // All over again with the versions in test::
    //
@@ -483,6 +491,10 @@
    test::modf(v1, &ll);
 #endif
    test::pow<2>(v1);
+ test::nextafter(v1, v1);
+ test::next_greater(v1);
+ test::next_less(v1);
+ test::edit_distance(v1, v1);
 }
 
 template <class RealType>

Added: sandbox/math_toolkit/libs/math/test/compile_test/sf_next_incl_test.cpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/libs/math/test/compile_test/sf_next_incl_test.cpp 2008-04-29 08:01:22 EDT (Tue, 29 Apr 2008)
@@ -0,0 +1,42 @@
+// Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Basic sanity check that header <boost/math/special_functions/next.hpp>
+// #includes all the files that it needs to.
+//
+#include <boost/math/special_functions/next.hpp>
+//
+// Note this header includes no other headers, this is
+// important if this test is to be meaningful:
+//
+#include "test_compile_result.hpp"
+
+void check()
+{
+ check_result<float>(boost::math::nextafter<float>(f, f));
+ check_result<double>(boost::math::nextafter<double>(d, d));
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+ check_result<long double>(boost::math::nextafter<long double>(l, l));
+#endif
+
+ check_result<float>(boost::math::next_greater<float>(f));
+ check_result<double>(boost::math::next_greater<double>(d));
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+ check_result<long double>(boost::math::next_greater<long double>(l));
+#endif
+
+ check_result<float>(boost::math::next_less<float>(f));
+ check_result<double>(boost::math::next_less<double>(d));
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+ check_result<long double>(boost::math::next_less<long double>(l));
+#endif
+
+ check_result<float>(boost::math::edit_distance<float>(f, f));
+ check_result<double>(boost::math::edit_distance<double>(d, d));
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+ check_result<long double>(boost::math::edit_distance<long double>(l, l));
+#endif
+
+}

Added: sandbox/math_toolkit/libs/math/test/test_next.cpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/libs/math/test/test_next.cpp 2008-04-29 08:01:22 EDT (Tue, 29 Apr 2008)
@@ -0,0 +1,102 @@
+// (C) Copyright John Maddock 2008.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/math/concepts/real_concept.hpp>
+#include <boost/test/included/test_exec_monitor.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+#include <boost/math/special_functions/next.hpp>
+
+template <class T>
+void test_value(const T& val, const char* name)
+{
+ using namespace boost::math;
+ T upper = tools::max_value<T>();
+ T lower = -upper;
+
+ std::cout << "Testing type " << name << " with initial value " << val << std::endl;
+
+ BOOST_CHECK_EQUAL(edit_distance(next_greater(val), val), 1);
+ BOOST_CHECK(next_greater(val) > val);
+ BOOST_CHECK_EQUAL(edit_distance(next_less(val), val), 1);
+ BOOST_CHECK(next_less(val) < val);
+ BOOST_CHECK_EQUAL(edit_distance(nextafter(val, upper), val), 1);
+ BOOST_CHECK(nextafter(val, upper) > val);
+ BOOST_CHECK_EQUAL(edit_distance(nextafter(val, lower), val), 1);
+ BOOST_CHECK(nextafter(val, lower) < val);
+ BOOST_CHECK_EQUAL(edit_distance(next_greater(next_greater(val)), val), 2);
+ BOOST_CHECK_EQUAL(edit_distance(next_less(next_less(val)), val), 2);
+ BOOST_CHECK_EQUAL(edit_distance(next_less(next_greater(val)), val), 0);
+ BOOST_CHECK_EQUAL(edit_distance(next_greater(next_less(val)), val), 0);
+ BOOST_CHECK_EQUAL(next_less(next_greater(val)), val);
+ BOOST_CHECK_EQUAL(next_greater(next_less(val)), val);
+}
+
+template <class T>
+void test_values(const T& val, const char* name)
+{
+ static const T a = static_cast<T>(1.3456724e22);
+ static const T b = static_cast<T>(1.3456724e-22);
+ static const T z = 0;
+ static const T one = 1;
+ static const T two = 2;
+
+ test_value(a, name);
+ test_value(-a, name);
+ test_value(b, name);
+ test_value(-b, name);
+ test_value(boost::math::tools::epsilon<T>(), name);
+ 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);
+ test_value(one, name);
+ test_value(-one, name);
+ test_value(two, name);
+ test_value(-two, name);
+ if(std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::has_denorm)
+ {
+ test_value(std::numeric_limits<T>::denorm_min(), name);
+ test_value(-std::numeric_limits<T>::denorm_min(), name);
+ test_value(2 * std::numeric_limits<T>::denorm_min(), name);
+ test_value(-2 * std::numeric_limits<T>::denorm_min(), name);
+ }
+
+ static const unsigned primes[] = {
+ 11, 13, 17, 19, 23, 29,
+ 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
+ 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
+ 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
+ 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
+ 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
+ 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
+ 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
+ 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
+ };
+
+ for(unsigned i = 0; i < sizeof(primes)/sizeof(primes[0]); ++i)
+ {
+ T v1 = val;
+ T v2 = val;
+ for(unsigned j = 0; j < primes[i]; ++j)
+ {
+ v1 = boost::math::next_greater(v1);
+ v2 = boost::math::next_less(v2);
+ }
+ BOOST_CHECK_EQUAL(boost::math::edit_distance(v1, val), primes[i]);
+ BOOST_CHECK_EQUAL(boost::math::edit_distance(v2, val), primes[i]);
+ }
+}
+
+int test_main(int, char* [])
+{
+ std::cout << boost::math::edit_distance(1.0, 0.0) << std::endl;
+ test_values(1.0f, "float");
+ test_values(1.0, "double");
+ test_values(1.0L, "long double");
+ test_values(boost::math::concepts::real_concept(0), "real_concept");
+ return 0;
+}
+


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