Boost logo

Boost-Commit :

From: john_at_[hidden]
Date: 2007-12-22 14:01:38


Author: johnmaddock
Date: 2007-12-22 14:01:37 EST (Sat, 22 Dec 2007)
New Revision: 42244
URL: http://svn.boost.org/trac/boost/changeset/42244

Log:
Added trunc, round and fmod family of functions.
Added:
   sandbox/math_toolkit/boost/math/special_functions/modf.hpp (contents, props changed)
   sandbox/math_toolkit/boost/math/special_functions/round.hpp (contents, props changed)
   sandbox/math_toolkit/boost/math/special_functions/trunc.hpp (contents, props changed)
   sandbox/math_toolkit/libs/math/test/test_round.cpp (contents, props changed)
Text files modified:
   sandbox/math_toolkit/libs/math/test/Jamfile.v2 | 1 +
   1 files changed, 1 insertions(+), 0 deletions(-)

Added: sandbox/math_toolkit/boost/math/special_functions/modf.hpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/boost/math/special_functions/modf.hpp 2007-12-22 14:01:37 EST (Sat, 22 Dec 2007)
@@ -0,0 +1,50 @@
+// Copyright John Maddock 2007.
+// 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_MODF_HPP
+#define BOOST_MATH_MODF_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+
+namespace boost{ namespace math{
+
+template <class T>
+inline T modf(const T& v, T* ipart)
+{
+ *ipart = trunc(v);
+ return v - *ipart;
+}
+
+template <class T>
+inline T modf(const T& v, int* ipart)
+{
+ *ipart = itrunc(v);
+ return v - *ipart;
+}
+
+template <class T>
+inline T modf(const T& v, long* ipart)
+{
+ *ipart = ltrunc(v);
+ return v - *ipart;
+}
+
+#ifdef BOOST_HAS_LONG_LONG
+template <class T>
+inline T modf(const T& v, long long* ipart)
+{
+ *ipart = lltrunc(v);
+ return v - *ipart;
+}
+#endif
+
+}} // namespaces
+
+#endif // BOOST_MATH_MODF_HPP

Added: sandbox/math_toolkit/boost/math/special_functions/round.hpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/boost/math/special_functions/round.hpp 2007-12-22 14:01:37 EST (Sat, 22 Dec 2007)
@@ -0,0 +1,56 @@
+// Copyright John Maddock 2007.
+// 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_ROUND_HPP
+#define BOOST_MATH_ROUND_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+
+namespace boost{ namespace math{
+
+template <class T>
+inline T round(const T& v)
+{
+ BOOST_MATH_STD_USING
+ return floor(v + 0.5f);
+}
+//
+// The following functions will not compile unless T has an
+// implicit convertion to the integer types. For user-defined
+// number types this will likely not be the case. In that case
+// these functions should either be specialized for the UDT in
+// question, or else overloads should be placed in the same
+// namespace as the UDT: these will then be found via argument
+// dependent lookup. See our concept archetypes for examples.
+//
+template <class T>
+inline int iround(const T& v)
+{
+ return static_cast<int>(boost::math::round(v));
+}
+
+template <class T>
+inline long lround(const T& v)
+{
+ return static_cast<long int>(boost::math::round(v));
+}
+
+#ifdef BOOST_HAS_LONG_LONG
+
+template <class T>
+inline long long llround(const T& v)
+{
+ return static_cast<long long>(boost::math::round(v));
+}
+
+#endif
+
+}} // namespaces
+
+#endif // BOOST_MATH_ROUND_HPP

Added: sandbox/math_toolkit/boost/math/special_functions/trunc.hpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/boost/math/special_functions/trunc.hpp 2007-12-22 14:01:37 EST (Sat, 22 Dec 2007)
@@ -0,0 +1,56 @@
+// Copyright John Maddock 2007.
+// 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_TRUNC_HPP
+#define BOOST_MATH_TRUNC_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+
+namespace boost{ namespace math{
+
+template <class T>
+inline T trunc(const T& v)
+{
+ BOOST_MATH_STD_USING
+ return (v >= 0) ? floor(v) : ceil(v);
+}
+//
+// The following functions will not compile unless T has an
+// implicit convertion to the integer types. For user-defined
+// number types this will likely not be the case. In that case
+// these functions should either be specialized for the UDT in
+// question, or else overloads should be placed in the same
+// namespace as the UDT: these will then be found via argument
+// dependent lookup. See our concept archetypes for examples.
+//
+template <class T>
+inline int itrunc(const T& v)
+{
+ return static_cast<int>(boost::math::trunc(v));
+}
+
+template <class T>
+inline long ltrunc(const T& v)
+{
+ return static_cast<long int>(boost::math::trunc(v));
+}
+
+#ifdef BOOST_HAS_LONG_LONG
+
+template <class T>
+inline long long lltrunc(const T& v)
+{
+ return static_cast<long long>(boost::math::trunc(v));
+}
+
+#endif
+
+}} // namespaces
+
+#endif // BOOST_MATH_TRUNC_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 2007-12-22 14:01:37 EST (Sat, 22 Dec 2007)
@@ -299,6 +299,7 @@
 
 run test_remez.cpp ;
 run test_roots.cpp ;
+run test_round.cpp ;
 run test_spherical_harmonic.cpp ;
 run test_students_t.cpp ;
 run test_tgamma_ratio.cpp ;

Added: sandbox/math_toolkit/libs/math/test/test_round.cpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/libs/math/test/test_round.cpp 2007-12-22 14:01:37 EST (Sat, 22 Dec 2007)
@@ -0,0 +1,176 @@
+// (C) Copyright John Maddock 2007.
+// 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/round.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+#include <boost/math/special_functions/modf.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <boost/random/mersenne_twister.hpp>
+
+boost::mt19937 rng;
+
+template <class T>
+T get_random()
+{
+ //
+ // Fill all the bits in T with random values,
+ // likewise set the exponent to a random value
+ // that will still fit inside a T, and always
+ // have a remainder as well as an integer part.
+ //
+ int bits = boost::math::tools::digits<T>();
+ int shift = 0;
+ int exponent = rng() % (bits - 4);
+ T result = 0;
+ while(bits > 0)
+ {
+ result += ldexp(static_cast<T>(rng()), shift);
+ shift += std::numeric_limits<int>::digits;
+ bits -= std::numeric_limits<int>::digits;
+ }
+ return rng() & 1u ? -ldexp(frexp(result, &bits), exponent) : ldexp(frexp(result, &bits), exponent);
+}
+
+template <class T, class U>
+void check_within_half(T a, U u)
+{
+ if(fabs(a-u) > 0.5f)
+ {
+ BOOST_ERROR("Rounded result differed by more than 0.5 from the original");
+ std::cerr << "Values were: " << std::setprecision(35) << std::setw(40)
+ << std::left << a << u << std::endl;
+ }
+}
+
+//
+// We may not have an abs overload for long long so provide a fall back:
+//
+template <class T>
+inline T safe_abs(T const& v ...)
+{
+ return v < 0 ? -v : v;
+}
+
+template <class T, class U>
+void check_trunc_result(T a, U u)
+{
+ BOOST_MATH_STD_USING
+ using ::abs;
+ if(fabs(a-u) >= 1)
+ {
+ BOOST_ERROR("Rounded result differed by more than 1 from the original");
+ std::cerr << "Values were: " << std::setprecision(35) << std::setw(40)
+ << std::left << a << u << std::endl;
+ }
+ if(abs(a) < safe_abs(u))
+ {
+ BOOST_ERROR("Truncated result had larger absolute value than the original");
+ std::cerr << "Values were: " << std::setprecision(35) << std::setw(40)
+ << std::left << a << u << std::endl;
+ }
+}
+
+template <class T, class U>
+void check_modf_result(T a, T fract, U ipart)
+{
+ BOOST_MATH_STD_USING
+ if(fract + ipart != a)
+ {
+ BOOST_ERROR("Fractional and integer results do not add up to the original value");
+ std::cerr << "Values were: " << std::setprecision(35) << " "
+ << std::left << a << ipart << " " << fract << std::endl;
+ }
+ if((boost::math::sign(a) != boost::math::sign(fract)) && boost::math::sign(fract))
+ {
+ BOOST_ERROR("Original and fractional parts have differing signs");
+ std::cerr << "Values were: " << std::setprecision(35) << " "
+ << std::left << a << ipart << " " << fract << std::endl;
+ }
+ if((boost::math::sign(a) != boost::math::sign(ipart)) && boost::math::sign(ipart))
+ {
+ BOOST_ERROR("Original and integer parts have differing signs");
+ std::cerr << "Values were: " << std::setprecision(35) << " "
+ << std::left << a << ipart << " " << ipart << std::endl;
+ }
+ if(fabs(a-ipart) >= 1)
+ {
+ BOOST_ERROR("Rounded result differed by more than 1 from the original");
+ std::cerr << "Values were: " << std::setprecision(35) << std::setw(40)
+ << std::left << a << ipart << std::endl;
+ }
+}
+
+template <class T>
+void test_round(T, const char* name)
+{
+ BOOST_MATH_STD_USING
+
+ for(int i = 0; i < 1000; ++i)
+ {
+ T arg = get_random<T>();
+ T r = boost::math::round(arg);
+ check_within_half(arg, r);
+ r = boost::math::trunc(arg);
+ check_trunc_result(arg, r);
+ T frac = boost::math::modf(arg, &r);
+ check_modf_result(arg, frac, r);
+
+ if(abs(r) < (std::numeric_limits<int>::max)())
+ {
+ int i = boost::math::iround(arg);
+ check_within_half(arg, i);
+ i = boost::math::itrunc(arg);
+ check_trunc_result(arg, i);
+ r = boost::math::modf(arg, &i);
+ check_modf_result(arg, r, i);
+ }
+
+ if(abs(r) < (std::numeric_limits<long>::max)())
+ {
+ long l = boost::math::lround(arg);
+ check_within_half(arg, l);
+ l = boost::math::ltrunc(arg);
+ check_trunc_result(arg, l);
+ r = boost::math::modf(arg, &l);
+ check_modf_result(arg, r, l);
+ }
+
+#ifdef BOOST_HAS_LONG_LONG
+ if(abs(r) < (std::numeric_limits<long long>::max)())
+ {
+ long long ll = boost::math::llround(arg);
+ check_within_half(arg, ll);
+ ll = boost::math::lltrunc(arg);
+ check_trunc_result(arg, ll);
+ r = boost::math::modf(arg, &ll);
+ check_modf_result(arg, r, ll);
+ }
+#endif
+ }
+}
+
+int test_main(int, char* [])
+{
+ test_round(0.1F, "float");
+ test_round(0.1, "double");
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+ test_round(0.1L, "long double");
+ //test_round(boost::math::concepts::real_concept(0.1), "real_concept");
+#else
+ std::cout << "<note>The long double tests have been disabled on this platform "
+ "either because the long double overloads of the usual math functions are "
+ "not available at all, or because they are too inaccurate for these tests "
+ "to pass.</note>" << std::cout;
+#endif
+ 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