// Boost.Units - A C++ library for zero-overhead dimensional analysis and // unit/quantity manipulation and conversion // // Copyright (C) 2003-2008 Matthias Christian Schabel // Copyright (C) 2007-2008 Steven Watanabe // // Distributed under 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_UNITS_CMATH_HPP #define BOOST_UNITS_CMATH_HPP #include <boost/config/no_tr1/cmath.hpp> #include <cstdlib> #include <boost/math/special_functions/fpclassify.hpp> #include <boost/math/special_functions/hypot.hpp> #include <boost/math/special_functions/next.hpp> #include <boost/math/special_functions/round.hpp> #include <boost/math/special_functions/sign.hpp> #include <boost/units/dimensionless_quantity.hpp> #include <boost/units/pow.hpp> #include <boost/units/quantity.hpp> #include <boost/units/detail/cmath_impl.hpp> #include <boost/units/detail/dimensionless_unit.hpp> #include <boost/units/systems/si/plane_angle.hpp> /// \file /// \brief Overloads of functions in \<cmath\> for quantities. /// \details Only functions for which a dimensionally-correct result type /// can be determined are overloaded. /// All functions work with dimensionless quantities. // BOOST_PREVENT_MACRO_SUBSTITUTION is needed on certain compilers that define // some <cmath> functions as macros; it is used for all functions even though it // isn't necessary -- I didn't want to think :) // // the form using namespace detail; return(f(x)); is used // to enable ADL for UDTs. namespace boost { namespace units { template<class Unit,class Y> inline bool isfinite BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using boost::math::isfinite; return isfinite BOOST_PREVENT_MACRO_SUBSTITUTION (q.value()); } template<class Unit,class Y> inline bool isinf BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using boost::math::isinf; return isinf BOOST_PREVENT_MACRO_SUBSTITUTION (q.value()); } template<class Unit,class Y> inline bool isnan BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using boost::math::isnan; return isnan BOOST_PREVENT_MACRO_SUBSTITUTION (q.value()); } template<class Unit,class Y> inline bool isnormal BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using boost::math::isnormal; return isnormal BOOST_PREVENT_MACRO_SUBSTITUTION (q.value()); } template<class Unit,class Y> inline bool isgreater BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; return isgreater BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value()); } template<class Unit,class Y> inline bool isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; return isgreaterequal BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value()); } template<class Unit,class Y> inline bool isless BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; return isless BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value()); } template<class Unit,class Y> inline bool islessequal BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; return islessequal BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value()); } template<class Unit,class Y> inline bool islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; return islessgreater BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value()); } template<class Unit,class Y> inline bool isunordered BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; return isunordered BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value()); } template<class Unit,class Y> inline quantity<Unit,Y> abs BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using std::abs; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(abs BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); } template<class Unit,class Y> inline quantity<Unit,Y> ceil BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using std::ceil; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(ceil BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); } template<class Unit,class Y> inline quantity<Unit,Y> copysign BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using boost::math::copysign; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(copysign BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value())); } template<class Unit,class Y> inline quantity<Unit,Y> fabs BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using std::fabs; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(fabs BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); } template<class Unit,class Y> inline quantity<Unit,Y> floor BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using std::floor; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(floor BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); } template<class Unit,class Y> inline quantity<Unit,Y> fdim BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(fdim BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value())); } #if 0 template<class Unit1,class Unit2,class Unit3,class Y> inline typename add_typeof_helper< typename multiply_typeof_helper<quantity<Unit1,Y>, quantity<Unit2,Y> >::type, quantity<Unit3,Y> >::type fma BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit1,Y>& q1, const quantity<Unit2,Y>& q2, const quantity<Unit3,Y>& q3) { using namespace detail; typedef quantity<Unit1,Y> type1; typedef quantity<Unit2,Y> type2; typedef quantity<Unit3,Y> type3; typedef typename multiply_typeof_helper<type1,type2>::type prod_type; typedef typename add_typeof_helper<prod_type,type3>::type quantity_type; return quantity_type::from_value(fma BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value(),q3.value())); } #endif template<class Unit,class Y> inline quantity<Unit,Y> fmax BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(fmax BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value())); } template<class Unit,class Y> inline quantity<Unit,Y> fmin BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using namespace detail; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(fmin BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value())); } template<class Unit,class Y> inline int fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using boost::math::fpclassify; return fpclassify BOOST_PREVENT_MACRO_SUBSTITUTION (q.value()); } template<class Unit,class Y> inline typename root_typeof_helper< typename add_typeof_helper< typename power_typeof_helper<quantity<Unit,Y>, static_rational<2> >::type, typename power_typeof_helper<quantity<Unit,Y>, static_rational<2> >::type>::type, static_rational<2> >::type hypot BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1,const quantity<Unit,Y>& q2) { using boost::math::hypot; typedef quantity<Unit,Y> type1; typedef typename power_typeof_helper<type1,static_rational<2> >::type pow_type; typedef typename add_typeof_helper<pow_type,pow_type>::type add_type; typedef typename root_typeof_helper<add_type,static_rational<2> >::type quantity_type; return quantity_type::from_value(hypot BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value())); } // does ISO C++ support long long? g++ claims not //template<class Unit,class Y> //inline //quantity<Unit,long long> //llrint BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) //{ // using namespace detail; // // typedef quantity<Unit,long long> quantity_type; // // return quantity_type::from_value(llrint BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); //} // does ISO C++ support long long? g++ claims not //template<class Unit,class Y> //inline //quantity<Unit,long long> //llround BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) //{ // using namespace detail; // // typedef quantity<Unit,long long> quantity_type; // // return quantity_type::from_value(llround BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); //} #if 0 template<class Unit,class Y> inline quantity<Unit,Y> nearbyint BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using namespace detail; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(nearbyint BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); } #endif template<class Unit,class Y> inline quantity<Unit,Y> nextafter BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using boost::math::nextafter; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(nextafter BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value())); } template<class Unit,class Y> inline quantity<Unit,Y> nexttoward BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { // the only difference between nextafter and nexttowards is // in the argument types. Since we are requiring identical // argument types, there is no difference. using boost::math::nextafter; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(nextafter BOOST_PREVENT_MACRO_SUBSTITUTION (q1.value(),q2.value())); } #if 0 template<class Unit,class Y> inline quantity<Unit,Y> rint BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using namespace detail; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(rint BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); } #endif template<class Unit,class Y> inline quantity<Unit,Y> round BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using boost::math::round; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(round BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); } template<class Unit,class Y> inline int signbit BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using boost::math::signbit; return signbit BOOST_PREVENT_MACRO_SUBSTITUTION (q.value()); } template<class Unit,class Y> inline quantity<Unit,Y> trunc BOOST_PREVENT_MACRO_SUBSTITUTION (const quantity<Unit,Y>& q) { using namespace detail; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(trunc BOOST_PREVENT_MACRO_SUBSTITUTION (q.value())); } template<class Unit,class Y> inline quantity<Unit, Y> fmod(const quantity<Unit,Y>& q1, const quantity<Unit,Y>& q2) { using std::fmod; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(fmod(q1.value(), q2.value())); } template<class Unit, class Y> inline quantity<Unit, Y> modf(const quantity<Unit, Y>& q1, quantity<Unit, Y>* q2) { using std::modf; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(modf(q1.value(), &quantity_cast<Y&>(*q2))); } template<class Unit, class Y, class Int> inline quantity<Unit, Y> frexp(const quantity<Unit, Y>& q,Int* ex) { using std::frexp; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(frexp(q.value(),ex)); } /// For non-dimensionless quantities, integral and rational powers /// and roots can be computed by @c pow<Ex> and @c root<Rt> respectively. template<class S, class Y> inline quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y> pow(const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q1, const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q2) { using std::pow; typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S),Y> quantity_type; return quantity_type::from_value(pow(q1.value(), q2.value())); } template<class S, class Y> inline quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y> exp(const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q) { using std::exp; typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y> quantity_type; return quantity_type::from_value(exp(q.value())); } template<class Unit, class Y, class Int> inline quantity<Unit, Y> ldexp(const quantity<Unit, Y>& q,const Int& ex) { using std::ldexp; typedef quantity<Unit,Y> quantity_type; return quantity_type::from_value(ldexp(q.value(), ex)); } template<class S, class Y> inline quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y> log(const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q) { using std::log; typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y> quantity_type; return quantity_type::from_value(log(q.value())); } template<class S, class Y> inline quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y> log10(const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q) { using std::log10; typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y> quantity_type; return quantity_type::from_value(log10(q.value())); } template<class Unit,class Y> inline typename root_typeof_helper< quantity<Unit,Y>, static_rational<2> >::type sqrt(const quantity<Unit,Y>& q) { using std::sqrt; typedef typename root_typeof_helper< quantity<Unit,Y>, static_rational<2> >::type quantity_type; return quantity_type::from_value(sqrt(q.value())); } } // namespace units } // namespace boost namespace boost { namespace units { // trig functions with si argument/return types /// cos of theta in radians template<class Y> typename dimensionless_quantity<si::system,Y>::type cos(const quantity<si::plane_angle,Y>& theta) { using std::cos; return cos(theta.value()); } /// sin of theta in radians template<class Y> typename dimensionless_quantity<si::system,Y>::type sin(const quantity<si::plane_angle,Y>& theta) { using std::sin; return sin(theta.value()); } /// tan of theta in radians template<class Y> typename dimensionless_quantity<si::system,Y>::type tan(const quantity<si::plane_angle,Y>& theta) { using std::tan; return tan(theta.value()); } /// cos of theta in other angular units template<class System,class Y> typename dimensionless_quantity<System,Y>::type cos(const quantity<unit<plane_angle_dimension,System>,Y>& theta) { return cos(quantity<si::plane_angle,Y>(theta)); } /// sin of theta in other angular units template<class System,class Y> typename dimensionless_quantity<System,Y>::type sin(const quantity<unit<plane_angle_dimension,System>,Y>& theta) { return sin(quantity<si::plane_angle,Y>(theta)); } /// tan of theta in other angular units template<class System,class Y> typename dimensionless_quantity<System,Y>::type tan(const quantity<unit<plane_angle_dimension,System>,Y>& theta) { return tan(quantity<si::plane_angle,Y>(theta)); } /// acos of dimensionless quantity returning angle in same system template<class Y,class System> quantity<unit<plane_angle_dimension, homogeneous_system<System> >,Y> acos(const quantity<unit<dimensionless_type, homogeneous_system<System> >,Y>& val) { using std::acos; return quantity<unit<plane_angle_dimension, homogeneous_system<System> >,Y>(acos(val.value())*si::radians); } /// acos of dimensionless quantity returning angle in radians template<class Y> quantity<angle::radian_base_unit::unit_type,Y> acos(const quantity<unit<dimensionless_type, heterogeneous_dimensionless_system>,Y>& val) { using std::acos; return quantity<angle::radian_base_unit::unit_type,Y>::from_value(acos(val.value())); } /// asin of dimensionless quantity returning angle in same system template<class Y,class System> quantity<unit<plane_angle_dimension, homogeneous_system<System> >,Y> asin(const quantity<unit<dimensionless_type, homogeneous_system<System> >,Y>& val) { using std::asin; return quantity<unit<plane_angle_dimension, homogeneous_system<System> >,Y>(asin(val.value())*si::radians); } /// asin of dimensionless quantity returning angle in radians template<class Y> quantity<angle::radian_base_unit::unit_type,Y> asin(const quantity<unit<dimensionless_type, heterogeneous_dimensionless_system>,Y>& val) { using std::asin; return quantity<angle::radian_base_unit::unit_type,Y>::from_value(asin(val.value())); } /// atan of dimensionless quantity returning angle in same system template<class Y,class System> quantity<unit<plane_angle_dimension, homogeneous_system<System> >,Y> atan(const quantity<unit<dimensionless_type, homogeneous_system<System> >, Y>& val) { using std::atan; return quantity<unit<plane_angle_dimension, homogeneous_system<System> >,Y>(atan(val.value())*si::radians); } /// atan of dimensionless quantity returning angle in radians template<class Y> quantity<angle::radian_base_unit::unit_type,Y> atan(const quantity<unit<dimensionless_type, heterogeneous_dimensionless_system>, Y>& val) { using std::atan; return quantity<angle::radian_base_unit::unit_type,Y>::from_value(atan(val.value())); } /// atan2 of @c value_type returning angle in radians template<class Y, class Dimension, class System> quantity<unit<plane_angle_dimension, homogeneous_system<System> >, Y> atan2(const quantity<unit<Dimension, homogeneous_system<System> >, Y>& y, const quantity<unit<Dimension, homogeneous_system<System> >, Y>& x) { using std::atan2; return quantity<unit<plane_angle_dimension, homogeneous_system<System> >, Y>(atan2(y.value(),x.value())*si::radians); } /// atan2 of @c value_type returning angle in radians template<class Y, class Dimension, class System> quantity<angle::radian_base_unit::unit_type,Y> atan2(const quantity<unit<Dimension, heterogeneous_system<System> >, Y>& y, const quantity<unit<Dimension, heterogeneous_system<System> >, Y>& x) { using std::atan2; return quantity<angle::radian_base_unit::unit_type,Y>::from_value(atan2(y.value(),x.value())); } } // namespace units } // namespace boost #endif // BOOST_UNITS_CMATH_HPP