Parent Directory
|
Revision Log
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