SCM Repositories - quan


Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1.4.3 - (download) (annotate) (vendor branch)
Thu Jul 13 02:10:34 2006 UTC (3 years ago) by kwikius
Branch: concept_08_July_2006-branch
CVS Tags: concept_08_July_2006_pre_merge_17_July_2006-tag
Changes since 1.1.1.1.4.2: +17 -9 lines
More work on dimensioned-multiply and divide calculations, and mods to get them and compare working on gcc4.0. line endings fixed on a couple of files
    1 #ifndef QUAN_DETAIL_DIMENSIONED_MULTIPLY1_HPP_INCLUDED
    2 #define QUAN_DETAIL_DIMENSIONED_MULTIPLY1_HPP_INCLUDED
    3 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
    4 #  pragma once
    5 #endif
    6 
    7 // Copyright Andrew Little 2006
    8 //
    9 // Distributed under the Boost Software License, Version 1.0.
   10 // (See accompanying file LICENSE_1_0.txt or copy at
   11 // http://www.boost.org/LICENSE_1_0.txt)
   12 //
   13 // See QUAN_ROOT/quan_matters/index.html for documentation.
   14 
   15 /*
   16 dimensioned multiply. Only unit_multipliers are involved at low level (IOW not unit_exponents):
   17 
   18 unitless_L = n_L * pow10<exponent_L>() * multiplier_L
   19 unitless_R = n_R * pow10<exponent_R>() * multiplier_R
   20 
   21 //unitless_result = unitless_L * unitless_R
   22 unitless_result =  n_L * pow10<exponentL> * pow10<exponent_R> * multiplier_L * multiplier_R;
   23 
   24 however the result_type is not unitless but uses pow10<exponent_L + exponent_R> so:
   25 
   26 result_pow10<exponent_L + exponent_R> = n_L * n_R * (multiplier_L * multiplier_R);
   27 
   28 Therefore only the multipliers are involved in the calc. The result value of the calc
   29 will be used to initialise a quantity (which is always an SI quantity) of the correct exponent
   30 
   31 */
   32 
   33 #include <quan/meta/binary_operation.hpp>
   34 #include <quan/meta/rational.hpp>
   35 #include <quan/quantity_traits.hpp>
   36 #include <boost/type_traits/is_float.hpp>
   37 #include <boost/type_traits/is_integral.hpp>
   38 #include <boost/mpl/and.hpp>
   39 #include <boost/mpl/or.hpp>
   40 #include <boost/mpl/eval_if.hpp>
   41 #include <boost/mpl/bool.hpp>
   42 
   43 /*
   44     In a dimensioned_multiply there are 3 ValueTypes involved.
   45     The 2 user ValueTypes of the quantities , and the minimum
   46     ValueType of the Multiplier calculation for preserving precision.
   47 
   48     Where the Multiplier ValueType and User resultType of a multiply on
   49     the user input types are both floats or integers
   50     then the user type is preferred even if "smaller".
   51     Otherwise the result_type of a theoretical multiply of all three is used
   52     quan::quantity_traits::default_float_type (usually a double) will be used
   53     for the multipliers float and QUAN_INT32 for an int
   54 
   55     The idea is that the user doesnt want a conversion to double,
   56     if the input types are floats or an unnecessary conversion to long,
   57     if the input types are ints and an integer multiplier will preserve precision.
   58 
   59     The compute_multiply_result_type metafunction computes this type.
   60 
   61 */
   62 namespace quan{ namespace detail{
   63 
   64     template <
   65         typename UserValueType_L,
   66         typename UserValueType_R,
   67         typename PrecisionPreservingMultiplierValue_type
   68     >
   69     struct compute_multiply_result_type{
   70         typedef typename quan::meta::binary_operation<
   71             UserValueType_L,
   72             quan::meta::times,
   73             UserValueType_R
   74         >::type preferred_user_result_type;
   75         typedef typename boost::mpl::if_<
   76             boost::mpl::or_<
   77                 boost::mpl::and_<
   78                     boost::is_integral<
   79                         preferred_user_result_type
   80                     >,
   81                     boost::is_integral<
   82                         PrecisionPreservingMultiplierValue_type
   83                     >
   84                 >,
   85                 boost::mpl::and_<
   86                     boost::is_float<
   87                         preferred_user_result_type
   88                     >,
   89                     boost::is_float<
   90                         PrecisionPreservingMultiplierValue_type
   91                     >
   92                 >
   93             >,
   94             preferred_user_result_type,
   95             typename quan::meta::binary_operation<
   96                 preferred_user_result_type,
   97                 quan::meta::times,
   98                 PrecisionPreservingMultiplierValue_type
   99             >::type
  100         >::type type;
  101     };
  102 
  103 // selected by the  dimensioned_multiply_function below
  104 // where the Multiplier is one
  105     struct unitary_multiplier_function{
  106         template <typename ValueType_L,typename ValueType_R>
  107         struct eval{
  108             typedef typename quan::meta::binary_operation<
  109             ValueType_L,quan::meta::times,ValueType_R
  110             >::type result_type;
  111             result_type operator()(ValueType_L const & lhs,ValueType_R const & rhs)const
  112             {
  113                 result_type result = static_cast<result_type>(lhs) * rhs ;
  114                 return result;
  115             }
  116             typedef eval type;
  117         };
  118         typedef unitary_multiplier_function type;
  119     };
  120 // selected by the  dimensioned_multiply_function below
  121 // where the Multiplier is not equal to 1 but is an integer
  122 
  123     template <typename Multiplier>
  124     struct non_unitary_integer_multiplier_function{
  125         typedef QUAN_INT32 preferred_multiplier_type;
  126         template <typename ValueType_L,typename ValueType_R>
  127         struct eval{
  128             typedef typename compute_multiply_result_type<
  129             ValueType_L,ValueType_R,preferred_multiplier_type
  130             >::type result_type;
  131             result_type operator()(ValueType_L const & lhs,ValueType_R const & rhs)const
  132             {
  133                 result_type result
  134                 = (static_cast<result_type>(lhs) * rhs )
  135                 * static_cast<result_type>(
  136                     static_cast<QUAN_INT32>(quan::meta::numerator<Multiplier>::value)
  137                 );
  138                 return result;
  139             }
  140             typedef eval type;
  141         };
  142         typedef non_unitary_integer_multiplier_function type;
  143     };
  144 
  145 // selected by the  dimensioned_multiply_function below
  146 // where the Multiplier is not equal to 1 and  is not an integer
  147 // but The two rationals have been evaluated to one rational at compile time
  148     template <typename Multiplier>
  149     struct non_unitary_float_multiplier_function{
  150         typedef typename quan::quantity_traits::default_value_type
  151         preferred_multiplier_type;
  152 
  153         template <typename ValueType_L,typename ValueType_R>
  154         struct eval{
  155             typedef typename compute_multiply_result_type<
  156             ValueType_L,ValueType_R,preferred_multiplier_type
  157             >::type result_type;
  158             result_type operator()(ValueType_L const & lhs,ValueType_R const & rhs)const
  159             {
  160                 result_type result
  161                 = (static_cast<result_type>(lhs) * rhs )
  162                 * (static_cast<result_type>( static_cast<QUAN_INT32>(quan::meta::numerator<Multiplier>::value))
  163                         / static_cast<QUAN_INT32>(quan::meta::denominator<Multiplier>::value));
  164                 return result;
  165             }
  166             typedef eval type;
  167         };
  168         typedef non_unitary_float_multiplier_function type;
  169     };
  170 
  171 /*
  172     The default multiplier_function has managed to do a compile time
  173     calculation on the two input StaticUnitMultipliers
  174     and reduced them to one multiplier but it isnt equal to 1.
  175     If the multiplier is not an integer then the multipliers preferred multiplier result_type is
  176     quan::quantity_traits::default_value_type, else QUAN_INT32, however the users types may override this.
  177 */
  178     template <typename Multiplier>
  179     struct dimensioned_multiply_function : boost::mpl::eval_if<
  180         boost::mpl::equal_to<
  181             typename Multiplier::type,typename quan::meta::one_type_of<Multiplier>::type
  182         >,
  183         unitary_multiplier_function,
  184         boost::mpl::eval_if<
  185             quan::meta::is_integer<typename Multiplier::type>,
  186             non_unitary_integer_multiplier_function<typename Multiplier::type>,
  187             non_unitary_float_multiplier_function<typename Multiplier::type>
  188         >
  189     >::type{};
  190 
  191 /*
  192     The pair version hasnt been able to reduce the two StaticUnitMultipliers
  193     so the result must do more run time calculations
  194     and the result_type must be a real type
  195 */
  196 
  197     template <typename Multiplier_L,typename Multiplier_R>
  198     struct dimensioned_multiply_pair_function{
  199         typedef typename Multiplier_L::type lhs_multiplier;
  200         typedef typename Multiplier_R::type rhs_multiplier;
  201         // The preferred type must be a float of some sort
  202         typedef typename quan::quantity_traits::default_value_type preferred_multiplier_type;
  203         template <typename ValueType_L,typename ValueType_R>
  204         struct eval{
  205             typedef typename compute_multiply_result_type<
  206             ValueType_L,ValueType_R,preferred_multiplier_type
  207             >::type result_type;
  208 
  209             result_type operator()(ValueType_L const & lhs,ValueType_R const & rhs)const
  210             {
  211                 result_type result
  212                 = (static_cast<result_type>(lhs) * rhs )
  213                 *(static_cast<result_type>( static_cast<result_type>(quan::meta::numerator<lhs_multiplier>::value))
  214                         / static_cast<QUAN_INT32>(quan::meta::denominator<lhs_multiplier>::value))
  215                     * (static_cast<result_type>(static_cast<result_type>(quan::meta::numerator<rhs_multiplier>::value))
  216                         / static_cast<QUAN_INT32>(quan::meta::denominator<rhs_multiplier>::value));
  217                 return result;
  218             }
  219             typedef eval type;
  220         };
  221         typedef dimensioned_multiply_pair_function type;
  222     };
  223 
  224 /*
  225     range_checking a rational before compile time multiplication
  226 */
  227     template <typename Rational>
  228     struct elements_in_multipliable_range : boost::mpl::bool_<(
  229         (-46340 <= quan::meta::numerator<typename Rational::type>::value)
  230         && (46340 >= quan::meta::numerator<typename Rational::type>::value)
  231         &&(-46340 <= quan::meta::denominator<typename Rational::type>::value)
  232         && (46340 >= quan::meta::denominator<typename Rational::type>::value)
  233     )>{};
  234 
  235 /*
  236     If (The numerators and denominators of  Multiplier_L and Multiplier_R
  237      are all in range )
  238     then do the compile time multiply
  239     and use dimensioned_multiply_function on the result,
  240     else if (you can cancel the numerators/denominators) do so and
  241      use dimensioned_multiply_function on the result,
  242     else operate on the pair of multipliers at runtime.
  243 
  244 */
  245 
  246     template <
  247         typename Multiplier_L,
  248         typename Multiplier_R
  249     >
  250     struct  dimensioned_multiply1 : boost::mpl::eval_if<
  251         boost::mpl::and_<
  252             elements_in_multipliable_range<typename Multiplier_L::type>,
  253             elements_in_multipliable_range<typename Multiplier_R::type>
  254         >,
  255         dimensioned_multiply_function<
  256             typename boost::mpl::eval_if<
  257                 boost::mpl::and_<
  258                     elements_in_multipliable_range<typename Multiplier_L::type>,
  259                     elements_in_multipliable_range<typename Multiplier_R::type>
  260                 >,
  261                 quan::meta::binary_operation<
  262                     typename Multiplier_L::type,quan::meta::times,typename Multiplier_R::type
  263                 >,
  264                 boost::mpl::void_
  265             >::type
  266         >,
  267         boost::mpl::eval_if_c<
  268             ( quan::meta::numerator<Multiplier_L>::value
  269                 == static_cast<QUAN_INT32>(quan::meta::denominator<Multiplier_R>::value)),
  270             dimensioned_multiply_function<
  271                 typename quan::meta::rational<
  272                     quan::meta::numerator<Multiplier_R>::value,
  273                     quan::meta::denominator<Multiplier_L>::value
  274                 >::type
  275             >,
  276             boost::mpl::eval_if_c<
  277                 ( quan::meta::numerator<Multiplier_R>::value
  278                     == static_cast<QUAN_INT32>(quan::meta::denominator<Multiplier_L>::value)),
  279                 dimensioned_multiply_function<
  280                     typename quan::meta::rational<
  281                         quan::meta::numerator<Multiplier_L>::value,
  282                         quan::meta::denominator<Multiplier_R>::value
  283                     >::type
  284                 >,
  285                 dimensioned_multiply_pair_function<
  286                     typename Multiplier_L::type,
  287                     typename Multiplier_R::type
  288                 >
  289             >
  290         >
  291     >::type {};
  292 
  293 }}//quan::detail
  294 
  295 #endif