Library for big numbers from http://www.ttmath.org/

Dependents:   PIDHeater82 Conceptcontroller_v_1_0 AlarmClockApp COG4050_adxl355_tilt ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ttmathdec.h Source File

ttmathdec.h

00001 /*
00002  * This file is a part of TTMath Bignum Library
00003  * and is distributed under the (new) BSD licence.
00004  * Author: Tomasz Sowa <t.sowa@ttmath.org>
00005  */
00006 
00007 /* 
00008  * Copyright (c) 2012, Tomasz Sowa
00009  * All rights reserved.
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are met:
00013  * 
00014  *  * Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  *    
00017  *  * Redistributions in binary form must reproduce the above copyright
00018  *    notice, this list of conditions and the following disclaimer in the
00019  *    documentation and/or other materials provided with the distribution.
00020  *    
00021  *  * Neither the name Tomasz Sowa nor the names of contributors to this
00022  *    project may be used to endorse or promote products derived
00023  *    from this software without specific prior written permission.
00024  *
00025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
00035  * THE POSSIBILITY OF SUCH DAMAGE.
00036  */
00037 
00038 #ifndef headerfilettmathdec
00039 #define headerfilettmathdec
00040 
00041 #include "ttmathtypes.h"
00042 #include "ttmaththreads.h"
00043 #include "ttmathuint.h"
00044 
00045 
00046 
00047 namespace ttmath
00048 {
00049 
00050 template<uint value_size, uint dec_digits>
00051 class Dec
00052 {
00053 public:
00054 
00055     UInt<value_size> value;
00056     unsigned char info;
00057 
00058 
00059     /*!
00060         Sign
00061         the mask of a bit from 'info' which means that there is a sign
00062         (when the bit is set)
00063     */
00064     #define TTMATH_DEC_SIGN 128
00065 
00066 
00067     /*!
00068         Not a number
00069         if this bit is set that there is not a valid number
00070     */
00071     #define TTMATH_DEC_NAN  64
00072 
00073 
00074 
00075 
00076     Dec()
00077     {
00078         info = TTMATH_DEC_NAN;
00079     }
00080 
00081 
00082     Dec(const char * s)
00083     {
00084         info = TTMATH_DEC_NAN;
00085         FromString(s);
00086     }
00087 
00088 
00089     Dec<value_size, dec_digits> & operator=(const char * s)
00090     {
00091         FromString(s);
00092 
00093     return *this;
00094     }
00095 
00096 
00097     uint  FromString(const char * s, const char ** after_source = 0, bool * value_read = 0)
00098     {
00099         return FromStringBase(s, after_source, value_read);
00100     }
00101 
00102 
00103     void ToString(std::string & result) const
00104     {
00105         ToStringBase(result);
00106     }
00107 
00108 
00109     /*!
00110         this method clears a specific bit in the 'info' variable
00111 
00112         bit is one of: 
00113     */
00114     void ClearInfoBit(unsigned char bit)
00115     {
00116         info = info & (~bit);
00117     }
00118 
00119 
00120     /*!
00121         this method sets a specific bit in the 'info' variable
00122 
00123         bit is one of: 
00124 
00125     */
00126     void SetInfoBit(unsigned char bit)
00127     {
00128         info = info | bit;
00129     }
00130 
00131 
00132     /*!
00133         this method returns true if a specific bit in the 'info' variable is set
00134 
00135         bit is one of: 
00136     */
00137     bool IsInfoBit(unsigned char bit) const
00138     {
00139         return (info & bit) != 0;
00140     }
00141 
00142 
00143     bool IsNan() const 
00144     {
00145         return IsInfoBit(TTMATH_DEC_NAN);
00146     }
00147 
00148 
00149     bool IsSign() const 
00150     {
00151         return IsInfoBit(TTMATH_DEC_SIGN);
00152     }
00153 
00154 
00155     /*!
00156         this method sets the sign
00157 
00158             e.g.
00159             -1 -> -1
00160             2  -> -2
00161 
00162         we do not check whether there is a zero or not, if you're using this method
00163         you must be sure that the value is (or will be afterwards) different from zero
00164     */
00165     void SetSign()
00166     {
00167         SetInfoBit(TTMATH_DEC_SIGN);
00168     }
00169 
00170 
00171     void SetNaN()
00172     {
00173         SetInfoBit(TTMATH_DEC_NAN);
00174     }
00175 
00176 
00177     void Abs ()
00178     {
00179         ClearInfoBit(TTMATH_DEC_SIGN);
00180     }
00181 
00182 
00183 
00184     uint  Add(const Dec<value_size, dec_digits> & arg)
00185     {
00186     uint  c = 0;
00187 
00188         if( IsSign() == arg.IsSign() )
00189         {
00190             c += value.Add(arg.value);        
00191         }
00192         else
00193         {
00194             bool is_sign;
00195 
00196             if( value > arg.value )
00197             {
00198                 is_sign = IsSign();
00199                 value.Sub(arg.value);
00200             }
00201             else
00202             {
00203                 is_sign = arg.IsSign();
00204                 UInt<value_size> temp(this->value);
00205                 value = arg.value;
00206                 value.Sub(temp);
00207             }
00208 
00209             is_sign ? SetSign() : Abs ();
00210         }
00211 
00212         if( c )
00213             SetNaN();
00214 
00215     return (c==0)? 0 : 1;
00216     }
00217 
00218 /*
00219     uint Sub(const Dec<value_size, dec_digits> & arg)
00220     {
00221     }
00222 */
00223 
00224 private:
00225 
00226 
00227 
00228 
00229 
00230 
00231 #ifndef TTMATH_MULTITHREADS
00232 
00233     /*!
00234     */
00235     void SetMultipler(UInt<value_size> & result)
00236     {
00237         // this guardian is initialized before the program runs (static POD type)
00238         static int guardian = 0;
00239         static UInt<value_size> multipler;
00240     
00241         if( guardian == 0 )
00242         {
00243             multipler = 10;
00244             multipler.Pow(dec_digits);
00245             guardian = 1;
00246         }
00247 
00248         result = multipler;
00249     }
00250 
00251 #else
00252 
00253     /*!
00254     */
00255     void SetMultipler(UInt<value_size> & result)
00256     {
00257         // this guardian is initialized before the program runs (static POD type)
00258         volatile static sig_atomic_t guardian = 0;
00259         static UInt<value_size> * pmultipler;
00260     
00261         // double-checked locking
00262         if( guardian == 0 )
00263         {
00264             ThreadLock thread_lock;
00265 
00266             // locking
00267             if( thread_lock.Lock() )
00268             {
00269                 static UInt<value_size> multipler;
00270 
00271                 if( guardian == 0 )
00272                 {
00273                     pmultipler = &multipler;
00274                     multipler = 10;
00275                     multipler.Pow(dec_digits);
00276                     guardian = 1;
00277                 }
00278             }
00279             else
00280             {
00281                 // there was a problem with locking, we store the result directly in 'result' object
00282                 result = 10;
00283                 result.Pow(dec_digits);
00284                 
00285             return;
00286             }
00287 
00288             // automatically unlocking
00289         }
00290 
00291         result = *pmultipler;
00292     }
00293 
00294 #endif
00295 
00296 
00297 
00298     /*!
00299         an auxiliary method for converting from a string
00300     */
00301     template<class char_type>
00302     uint  FromStringBase(const char_type * s, const char_type ** after_source = 0, bool * value_read = 0)
00303     {
00304         UInt<value_size> multipler;
00305         const char_type * after;
00306         uint  c = 0;
00307         info = 0;
00308 
00309         Misc::SkipWhiteCharacters(s);
00310 
00311         if( *s == '-' )
00312         {
00313             s += 1;
00314             SetSign();
00315         }
00316         else
00317         if( *s == '+' )
00318         {
00319             s += 1;
00320         }
00321 
00322         c += value.FromString(s, 10, &after, value_read);
00323 
00324         if( after_source )
00325             *after_source = after;
00326 
00327         SetMultipler(multipler);
00328         c += value.Mul(multipler);
00329 
00330         if( *after == '.' )
00331             c += FromStringBaseAfterComma(after+1, after_source);
00332 
00333         if( c )
00334             SetInfoBit(TTMATH_DEC_NAN);
00335 
00336     return (c==0)? 0 : 1;
00337     }
00338 
00339 
00340     template<class char_type>
00341     uint  FromStringBaseAfterComma(const char_type * s, const char_type ** after_source = 0, bool * value_read = 0)
00342     {
00343         UInt<value_size> temp;
00344         UInt<value_size> multipler;
00345         sint z;
00346         uint  c = 0;
00347         size_t i = dec_digits;
00348 
00349         SetMultipler(multipler);
00350 
00351         for( ; i>0 && (z=Misc::CharToDigit (*s, 10)) != -1 ; --i, ++s )
00352         {
00353             multipler.DivInt(10);
00354             temp.SetZero();
00355 
00356             if( value_read )
00357                 *value_read = true;
00358 
00359             if( c == 0 )
00360             {
00361                 temp.table[0] = z;
00362                 c += temp.Mul(multipler);
00363                 c += value.Add(temp);
00364             }
00365         }
00366 
00367         if( i == 0 && (z=Misc::CharToDigit (*s, 10)) != -1 && z >= 5 )
00368             c += value.AddOne();
00369 
00370         if( after_source )
00371         {
00372             while( (z=Misc::CharToDigit (*s, 10)) != -1 )
00373                 s += 1;
00374 
00375             *after_source = s;
00376         }
00377 
00378     return c;
00379     }
00380 
00381 
00382 
00383     template<class string_type>
00384     void ToStringBase(string_type & result) const
00385     {
00386         if( IsNan() )
00387         {
00388             result = "NaN";
00389             return;
00390         }
00391 
00392         value.ToStringBase(result, 10, IsSign());
00393 
00394         if( dec_digits > 0 )
00395         {
00396             size_t size = result.size();
00397 
00398             if( IsSign() && size > 0 )
00399                 size -= 1;
00400 
00401             if( dec_digits >= size )
00402             {
00403                 size_t zeroes = dec_digits - size + 1;
00404                 size_t start  = IsSign() ? 1 : 0;
00405                 result.insert(start, zeroes, '0');
00406             }
00407 
00408             result.insert(result.end() - dec_digits, '.');
00409         }
00410     }
00411 
00412 
00413 
00414 };
00415 
00416 
00417 } // namespace
00418 
00419 #endif
00420