00001
00002
00003 #ifndef LHCBMATH_DIGIT_H
00004 #define LHCBMATH_DIGIT_H 1
00005
00006
00007
00008
00009
00010 #include "LHCbMath/TypeWrapper.h"
00011 #include "LHCbMath/IPower.hpp"
00012 #include "LHCbMath/Power.h"
00013
00014
00015
00016 #include "boost/integer_traits.hpp"
00017 #include "boost/static_assert.hpp"
00018
00059
00060 namespace Gaudi
00061 {
00062 namespace Math
00063 {
00064 namespace detail
00065 {
00066
00079 template <class TYPE,unsigned int N>
00080 struct Check10
00081 {
00082
00083 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00084 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00085 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00086
00087 enum
00088 {
00090 safe = ( N < (unsigned int) boost::integer_traits<TYPE>::digits10 ) ,
00092 value = ( N <= (unsigned int) boost::integer_traits<TYPE>::digits10 )
00093 } ;
00094
00095 };
00096
00107 template <class TYPE,
00108 typename TypeWrapper<TYPE>::value_type I ,
00109 unsigned int N>
00110 struct _IDigit
00111 {
00112
00113 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00114 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00115 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00116
00117 enum
00118 {
00119 value =
00120 Check10<TYPE,N>::safe ?
00121 (I/Gaudi::Math::IPower<TYPE ,10,N>::value )%10 :
00122 (I/Gaudi::Math::IPower<unsigned long long,10,N>::value )%10
00123 } ;
00124 private:
00125
00126 enum {
00127 _imax10 = boost::integer_traits<TYPE>::digits10 ,
00128 check = N <= _imax10
00129 } ;
00130
00131 BOOST_STATIC_ASSERT( check ) ;
00132
00133 } ;
00134
00144 template <class TYPE,
00145 typename TypeWrapper<TYPE>::value_type I ,
00146 unsigned int N1 ,
00147 unsigned int N2 >
00148 struct _IDigits
00149 {
00150
00151 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00152 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00153 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00154
00155 enum
00156 {
00157 value =
00158 Check10<TYPE,N1>::safe && Check10<TYPE,N2-N1>::safe ?
00159 (I/Gaudi::Math::IPower<TYPE ,10,N1>::value )%
00160 Gaudi::Math::IPower<TYPE,10,N2-N1>::value :
00161 (I/Gaudi::Math::IPower<unsigned long long,10,N1>::value )%
00162 Gaudi::Math::IPower<unsigned long long,10,N2-N1>::value
00163 };
00164
00165 private:
00166
00167 enum {
00168 _imax10 = boost::integer_traits<TYPE>::digits10 ,
00169 check1 = N1 < N2 ,
00170 check2 = N1 <= _imax10 ,
00171 check3 = N2 <= _imax10 + 1
00172 } ;
00173
00174 BOOST_STATIC_ASSERT( check1 ) ;
00175 BOOST_STATIC_ASSERT( check2 ) ;
00176 BOOST_STATIC_ASSERT( check3 ) ;
00177
00178 } ;
00179
00188 template <class TYPE, unsigned int N>
00189 struct _Digit : public std::unary_function<TYPE,int>
00190 {
00191
00192 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00193 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00194 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00195
00196 enum { value = Gaudi::Math::IPower<unsigned long long,10,N>::value } ;
00197
00198 inline int operator () ( const TYPE v ) const { return (v/value)%10 ; }
00199
00200 private:
00201
00202 enum {
00203 _imax10 = boost::integer_traits<TYPE>::digits10
00204 } ;
00205
00206 BOOST_STATIC_ASSERT( N <= _imax10 ) ;
00207
00208 } ;
00209
00210 template <class TYPE, unsigned int N, bool OK>
00211 struct __Dig10
00212 { enum { value = Gaudi::Math::IPower<TYPE,10,N>::value } ; } ;
00213
00214 template <class TYPE, unsigned int N>
00215 struct __Dig10<TYPE,N,false>
00216 { enum { value = Gaudi::Math::IPower<unsigned long long,10,N>::value } ; } ;
00217
00227 template <class TYPE,
00228 unsigned int N1,
00229 unsigned int N2>
00230 struct _Digits : public std::unary_function<TYPE,int>
00231 {
00232 private:
00233
00234 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00235 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00236 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00237
00238 enum
00239 {
00240 val1 = __Dig10<TYPE,N1,
00241 Check10<TYPE,N1>::safe && Check10<TYPE,N2-N1>::safe>:: value ,
00242 val2 = __Dig10<TYPE,N2-N1,
00243 Check10<TYPE,N1>::safe && Check10<TYPE,N2-N1>::safe>:: value
00244 } ;
00245
00246 public:
00247
00249 inline int operator() ( const TYPE v ) const { return (v/val1)%val2 ; }
00250
00251 private:
00252
00253 enum {
00254 _imax10 = boost::integer_traits<TYPE>::digits10
00255 } ;
00256
00257 BOOST_STATIC_ASSERT( N1 < N2 ) ;
00258 BOOST_STATIC_ASSERT( N1 <= _imax10 ) ;
00259 BOOST_STATIC_ASSERT( N2 <= _imax10 + 1 ) ;
00260
00261 };
00262 }
00263
00279
00280 template <class TYPE,
00281 typename Gaudi::Math::TypeWrapper<TYPE>::value_type I ,
00282 unsigned int N>
00283 struct IDigit : public detail::_IDigit<TYPE,I,N>
00284 {
00285
00286 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00287 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00288 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00289
00290 };
00291
00308 template <class TYPE,
00309 typename Gaudi::Math::TypeWrapper<TYPE>::value_type I ,
00310 unsigned int N1 ,
00311 unsigned int N2 >
00312 struct IDigits : public detail::_IDigits<TYPE,I,N1,N2>
00313 {
00314
00315 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00316 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00317 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00318
00319 };
00320
00340 template <class TYPE, unsigned int N>
00341 struct Digit : public detail::_Digit<TYPE,N>
00342 {
00343
00344 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00345 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00346 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00347
00348 };
00349
00369 template <class TYPE ,
00370 unsigned int N1 ,
00371 unsigned int N2 >
00372 struct Digits : public detail::_Digits<TYPE,N1,N2>
00373 {
00374
00375 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_specialized ) ;
00376 BOOST_STATIC_ASSERT( boost::integer_traits<TYPE>::is_integral ) ;
00377 BOOST_STATIC_ASSERT( !boost::integer_traits<TYPE>::is_signed ) ;
00378
00379 };
00380
00398 template <class TYPE>
00399 inline TYPE digit ( const TYPE value , const unsigned int N )
00400 {
00401
00402 BOOST_STATIC_ASSERT ( boost::integer_traits<TYPE>::is_specialized ) ;
00403 BOOST_STATIC_ASSERT ( boost::integer_traits<TYPE>::is_integral ) ;
00404 BOOST_STATIC_ASSERT ( !boost::integer_traits<TYPE>::is_signed ) ;
00405
00406 if ( N > (unsigned int) boost::integer_traits<TYPE>::digits10 ) { return 0 ; }
00407 else if ( N < (unsigned int) boost::integer_traits<TYPE>::digits10 )
00408 {
00409
00410 const TYPE ten = 10 ;
00411 const TYPE aux = Gaudi::Math::pow ( ten , N ) ;
00412 return (value/aux)%10 ;
00413
00414 }
00415
00416 const unsigned long long val = value ;
00417 const unsigned long long ten = 10 ;
00418 const unsigned long long aux = Gaudi::Math::pow ( ten , N ) ;
00419 return (val/aux)%10 ;
00420
00421 }
00422
00441 template <class TYPE>
00442 inline TYPE digits ( const TYPE value ,
00443 const unsigned int N1 ,
00444 const unsigned int N2 )
00445 {
00446
00447 BOOST_STATIC_ASSERT ( boost::integer_traits<TYPE>::is_specialized ) ;
00448 BOOST_STATIC_ASSERT ( boost::integer_traits<TYPE>::is_integral ) ;
00449 BOOST_STATIC_ASSERT ( !boost::integer_traits<TYPE>::is_signed ) ;
00450
00451 if ( N2 > 1 + boost::integer_traits<TYPE>::digits10 )
00452 { return digits ( value , N1 , 1 + boost::integer_traits<TYPE>::digits10 ) ; }
00453
00454 if ( N1 >= N2 ||
00455 N1 > (unsigned int) boost::integer_traits<TYPE>::digits10 )
00456 { return 0 ; }
00457
00458 if ( N1 < (unsigned int) boost::integer_traits<TYPE>::digits10 &&
00459 N2 - N1 < (unsigned int) boost::integer_traits<TYPE>::digits10 )
00460 {
00461
00462 const TYPE ten = 10 ;
00463 const TYPE aux1 = Gaudi::Math::pow ( ten , N1 ) ;
00464 const TYPE aux2 = Gaudi::Math::pow ( ten , N2 - N1 ) ;
00465 return (value/aux1)%aux2 ;
00466
00467 }
00468
00469 const unsigned long long val = value ;
00470 const unsigned long long ten = 10 ;
00471 const unsigned long long aux1 = Gaudi::Math::pow ( ten , N1 ) ;
00472 const unsigned long long aux2 = Gaudi::Math::pow ( ten , N2 - N1 ) ;
00473 return (val/aux1)%aux2 ;
00474
00475 }
00476
00477 }
00478 }
00479
00480
00481
00482 #endif // LHCBMATH_DIGIT_H
00483