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 ttmathobjects.h Source File

ttmathobjects.h

Go to the documentation of this file.
00001 /*
00002  * This file is a part of TTMath Mathematical Library
00003  * and is distributed under the (new) BSD licence.
00004  * Author: Tomasz Sowa <t.sowa@ttmath.org>
00005  */
00006 
00007 /* 
00008  * Copyright (c) 2006-2010, 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 
00039 #ifndef headerfilettmathobject
00040 #define headerfilettmathobject
00041 
00042 /*!
00043     \file ttmathobjects.h
00044     \brief Mathematic functions.
00045 */
00046 
00047 #include <string>
00048 #include <vector>
00049 #include <list>
00050 #include <map>
00051 
00052 #include "ttmathtypes.h"
00053 #include "ttmathmisc.h"
00054 
00055 
00056 namespace ttmath
00057 {
00058 
00059 /*!
00060     objects of this class are used with the mathematical parser
00061     they hold variables or functions defined by a user
00062 
00063     each object has its own table in which we're keeping variables or functions
00064 */
00065 class Objects 
00066 {
00067 public:
00068 
00069 
00070     /*!
00071         one item (variable or function)
00072         'items' will be on the table
00073     */
00074     struct Item 
00075     {
00076         // name of a variable of a function
00077         // internally we store variables and funcions as std::string (not std::wstring even when wide characters are used)
00078         std::string value;
00079 
00080         // number of parameters required by the function
00081         // (if there's a variable this 'param' is ignored)
00082         int param;
00083 
00084         Item () {}
00085         Item (const std::string & v, int p) : value(v), param(p) {}
00086     };
00087 
00088     // 'Table' is the type of our table
00089     typedef std::map<std::string, Item> Table;
00090     typedef    Table::iterator Iterator;
00091     typedef    Table::const_iterator CIterator;
00092 
00093 
00094 
00095     /*!
00096         this method returns true if a character 'c' is a character
00097         which can be in a name
00098         
00099         if 'can_be_digit' is true that means when the 'c' is a digit this 
00100         method returns true otherwise it returns false
00101     */
00102     static bool CorrectCharacter (int c, bool can_be_digit)
00103     {
00104         if( (c>='a' && c<='z') || (c>='A' && c<='Z') )
00105             return true;
00106 
00107         if( can_be_digit && ((c>='0' && c<='9') || c=='_') )
00108             return true;
00109 
00110     return false;
00111     }
00112 
00113 
00114     /*!
00115         this method returns true if the name can be as a name of an object
00116     */
00117     template<class string_type>
00118     static bool IsNameCorrect (const string_type & name)
00119     {
00120         if( name.empty() )
00121             return false;
00122 
00123         if( !CorrectCharacter (name[0], false) )
00124             return false;
00125 
00126         typename string_type::const_iterator i = name.begin();
00127 
00128         for(++i ; i!=name.end() ; ++i)
00129             if( !CorrectCharacter (*i, true) )
00130                 return false;
00131         
00132     return true;
00133     }
00134 
00135 
00136     /*!
00137         this method returns true if such an object is defined (name exists)
00138     */
00139     bool IsDefined (const std::string & name)
00140     {
00141         Iterator i = table.find(name);
00142 
00143         if( i != table.end() )
00144             // we have this object in our table
00145             return true;
00146 
00147     return false;
00148     }
00149 
00150 
00151 
00152 #ifndef TTMATH_DONT_USE_WCHAR
00153 
00154     /*!
00155         this method returns true if such an object is defined (name exists)
00156     */
00157     bool IsDefined (const std::wstring & name)
00158     {
00159         // we should check whether the name (in wide characters) are correct
00160         // before calling AssignString() function
00161         if( !IsNameCorrect (name) )
00162             return false;
00163 
00164         Misc::AssignString (str_tmp1, name);
00165 
00166     return IsDefined (str_tmp1);
00167     }
00168 
00169 #endif
00170 
00171 
00172     /*!
00173         this method adds one object (variable of function) into the table
00174     */
00175     ErrorCode  Add (const std::string & name, const std::string & value, int param = 0)
00176     {
00177         if( !IsNameCorrect (name) )
00178             return err_incorrect_name;
00179 
00180         Iterator i = table.find(name);
00181 
00182         if( i != table.end() )
00183             // we have this object in our table
00184             return err_object_exists;
00185 
00186         table.insert( std::make_pair(name, Item (value, param)) );
00187 
00188     return err_ok;
00189     }
00190 
00191 
00192 #ifndef TTMATH_DONT_USE_WCHAR
00193 
00194     /*!
00195         this method adds one object (variable of function) into the table
00196     */
00197     ErrorCode  Add (const std::wstring & name, const std::wstring & value, int param = 0)
00198     {
00199         // we should check whether the name (in wide characters) are correct
00200         // before calling AssignString() function
00201         if( !IsNameCorrect (name) )
00202             return err_incorrect_name;
00203 
00204         Misc::AssignString (str_tmp1, name);
00205         Misc::AssignString (str_tmp2, value);
00206         
00207     return Add (str_tmp1, str_tmp2, param);
00208     }
00209 
00210 #endif
00211 
00212 
00213     /*!
00214         this method returns 'true' if the table is empty
00215     */
00216     bool Empty () const
00217     {
00218         return table.empty();
00219     }
00220 
00221 
00222     /*!
00223         this method clears the table
00224     */
00225     void Clear ()
00226     {
00227         return table.clear();
00228     }
00229 
00230 
00231     /*!
00232         this method returns 'const_iterator' on the first item on the table
00233     */
00234     CIterator Begin () const
00235     {
00236         return table.begin();
00237     }
00238 
00239 
00240     /*!
00241         this method returns 'const_iterator' pointing at the space after last item
00242         (returns table.end())
00243     */
00244     CIterator End () const
00245     {
00246         return table.end();
00247     }
00248 
00249 
00250     /*!
00251         this method changes the value and the number of parameters for a specific object
00252     */
00253     ErrorCode  EditValue (const std::string & name, const std::string & value, int param = 0)
00254     {
00255         if( !IsNameCorrect (name) )
00256             return err_incorrect_name;
00257 
00258         Iterator i = table.find(name);
00259 
00260         if( i == table.end() )
00261             return err_unknown_object;
00262     
00263         i->second.value = value;
00264         i->second.param = param;
00265 
00266     return err_ok;
00267     }
00268 
00269 
00270 #ifndef TTMATH_DONT_USE_WCHAR
00271 
00272 
00273     /*!
00274         this method changes the value and the number of parameters for a specific object
00275     */
00276     ErrorCode  EditValue (const std::wstring & name, const std::wstring & value, int param = 0)
00277     {
00278         // we should check whether the name (in wide characters) are correct
00279         // before calling AssignString() function
00280         if( !IsNameCorrect (name) )
00281             return err_incorrect_name;
00282 
00283         Misc::AssignString (str_tmp1, name);
00284         Misc::AssignString (str_tmp2, value);
00285         
00286     return EditValue (str_tmp1, str_tmp2, param);
00287     }
00288 
00289 #endif
00290 
00291 
00292     /*!
00293         this method changes the name of a specific object
00294     */
00295     ErrorCode  EditName (const std::string & old_name, const std::string & new_name)
00296     {
00297         if( !IsNameCorrect (old_name) || !IsNameCorrect (new_name) )
00298             return err_incorrect_name;
00299 
00300         Iterator old_i = table.find(old_name);
00301         if( old_i == table.end() )
00302             return err_unknown_object;
00303         
00304         if( old_name == new_name )
00305             // the new name is the same as the old one
00306             // we treat it as a normal situation
00307             return err_ok;
00308 
00309         ErrorCode  err = Add (new_name, old_i->second.value, old_i->second.param);
00310         
00311         if( err == err_ok ) 
00312         {
00313             old_i = table.find(old_name);
00314             TTMATH_ASSERT( old_i != table.end() )
00315 
00316             table.erase(old_i);
00317         }
00318 
00319     return err;
00320     }
00321 
00322 
00323 
00324 #ifndef TTMATH_DONT_USE_WCHAR
00325 
00326 
00327     /*!
00328         this method changes the name of a specific object
00329     */
00330     ErrorCode  EditName (const std::wstring & old_name, const std::wstring & new_name)
00331     {
00332         // we should check whether the name (in wide characters) are correct
00333         // before calling AssignString() function
00334         if( !IsNameCorrect (old_name) || !IsNameCorrect (new_name) )
00335             return err_incorrect_name;
00336 
00337         Misc::AssignString (str_tmp1, old_name);
00338         Misc::AssignString (str_tmp2, new_name);
00339 
00340     return EditName (str_tmp1, str_tmp2);
00341     }
00342 
00343 #endif
00344 
00345 
00346     /*!
00347         this method deletes an object
00348     */
00349     ErrorCode  Delete (const std::string & name)
00350     {
00351         if( !IsNameCorrect (name) )
00352             return err_incorrect_name;
00353 
00354         Iterator i = table.find(name);
00355 
00356         if( i == table.end() )
00357             return err_unknown_object;
00358 
00359         table.erase( i );
00360 
00361     return err_ok;
00362     }
00363 
00364 
00365 #ifndef TTMATH_DONT_USE_WCHAR
00366 
00367 
00368     /*!
00369         this method deletes an object
00370     */
00371     ErrorCode  Delete (const std::wstring & name)
00372     {
00373         // we should check whether the name (in wide characters) are correct
00374         // before calling AssignString() function
00375         if( !IsNameCorrect (name) )
00376             return err_incorrect_name;
00377 
00378         Misc::AssignString (str_tmp1, name);
00379 
00380     return Delete (str_tmp1);
00381     }    
00382         
00383 #endif
00384 
00385 
00386     /*!
00387         this method gets the value of a specific object
00388     */
00389     ErrorCode  GetValue (const std::string & name, std::string & value) const
00390     {
00391         if( !IsNameCorrect (name) )
00392             return err_incorrect_name;
00393 
00394         CIterator i = table.find(name);
00395 
00396         if( i == table.end() )
00397         {
00398             value.clear();
00399             return err_unknown_object;
00400         }
00401 
00402         value = i->second.value;
00403 
00404     return err_ok;
00405     }
00406 
00407 
00408 #ifndef TTMATH_DONT_USE_WCHAR
00409 
00410     /*!
00411         this method gets the value of a specific object
00412     */
00413     ErrorCode  GetValue (const std::wstring & name, std::wstring & value)
00414     {
00415         // we should check whether the name (in wide characters) are correct
00416         // before calling AssignString() function
00417         if( !IsNameCorrect (name) )
00418             return err_incorrect_name;
00419 
00420         Misc::AssignString (str_tmp1, name);
00421         ErrorCode  err = GetValue (str_tmp1, str_tmp2);
00422         Misc::AssignString (value, str_tmp2);
00423 
00424     return err;
00425     }
00426 
00427 #endif
00428 
00429 
00430     /*!
00431         this method gets the value of a specific object
00432         (this version is used for not copying the whole string)
00433     */
00434     ErrorCode  GetValue (const std::string & name, const char ** value) const
00435     {
00436         if( !IsNameCorrect (name) )
00437             return err_incorrect_name;
00438 
00439         CIterator i = table.find(name);
00440 
00441         if( i == table.end() )
00442         {
00443             *value = 0;
00444             return err_unknown_object;
00445         }
00446 
00447         *value = i->second.value.c_str();
00448 
00449     return err_ok;
00450     }
00451 
00452 
00453 #ifndef TTMATH_DONT_USE_WCHAR
00454 
00455     /*!
00456         this method gets the value of a specific object
00457         (this version is used for not copying the whole string)
00458     */
00459     ErrorCode  GetValue (const std::wstring & name, const char ** value)
00460     {
00461         // we should check whether the name (in wide characters) are correct
00462         // before calling AssignString() function
00463         if( !IsNameCorrect (name) )
00464             return err_incorrect_name;
00465 
00466         Misc::AssignString (str_tmp1, name);
00467 
00468     return GetValue (str_tmp1, value);
00469     }
00470 
00471 #endif
00472 
00473 
00474     /*!
00475         this method gets the value and the number of parameters
00476         of a specific object
00477     */
00478     ErrorCode  GetValueAndParam (const std::string & name, std::string & value, int * param) const
00479     {
00480         if( !IsNameCorrect (name) )
00481             return err_incorrect_name;
00482 
00483         CIterator i = table.find(name);
00484 
00485         if( i == table.end() )
00486         {
00487             value.empty();
00488             *param = 0;
00489             return err_unknown_object;
00490         }
00491 
00492         value = i->second.value;
00493         *param = i->second.param;
00494 
00495     return err_ok;
00496     }
00497 
00498 
00499 #ifndef TTMATH_DONT_USE_WCHAR
00500 
00501     /*!
00502         this method gets the value and the number of parameters
00503         of a specific object
00504     */
00505     ErrorCode  GetValueAndParam (const std::wstring & name, std::wstring & value, int * param)
00506     {
00507         // we should check whether the name (in wide characters) are correct
00508         // before calling AssignString() function
00509         if( !IsNameCorrect (name) )
00510             return err_incorrect_name;
00511 
00512         Misc::AssignString (str_tmp1, name);
00513         ErrorCode  err = GetValueAndParam (str_tmp1, str_tmp2, param);
00514         Misc::AssignString (value, str_tmp2);
00515 
00516     return err;
00517     }
00518 
00519 #endif
00520 
00521 
00522     /*!
00523         this method sets the value and the number of parameters
00524         of a specific object
00525         (this version is used for not copying the whole string)
00526     */
00527     ErrorCode  GetValueAndParam (const std::string & name, const char ** value, int * param) const
00528     {
00529         if( !IsNameCorrect (name) )
00530             return err_incorrect_name;
00531 
00532         CIterator i = table.find(name);
00533 
00534         if( i == table.end() )
00535         {
00536             *value = 0;
00537             *param = 0;
00538             return err_unknown_object;
00539         }
00540 
00541         *value = i->second.value.c_str();
00542         *param = i->second.param;
00543 
00544     return err_ok;
00545     }
00546 
00547 
00548 #ifndef TTMATH_DONT_USE_WCHAR
00549 
00550 
00551     /*!
00552         this method sets the value and the number of parameters
00553         of a specific object
00554         (this version is used for not copying the whole string
00555         but in fact we make one copying during AssignString())
00556     */
00557     ErrorCode  GetValueAndParam (const std::wstring & name, const char ** value, int * param)
00558     {
00559         // we should check whether the name (in wide characters) are correct
00560         // before calling AssignString() function
00561         if( !IsNameCorrect (name) )
00562             return err_incorrect_name;
00563 
00564         Misc::AssignString (str_tmp1, name);
00565 
00566     return GetValueAndParam (str_tmp1, value, param);
00567     }
00568 
00569 
00570 #endif
00571 
00572 
00573     /*!
00574         this method returns a pointer into the table
00575     */
00576     Table * GetTable ()
00577     {
00578         return &table;
00579     }
00580 
00581 
00582 private:
00583 
00584     Table table;
00585     std::string str_tmp1, str_tmp2;
00586 
00587 }; // end of class Objects
00588 
00589 
00590 
00591 
00592 
00593 
00594 
00595 /*!
00596     objects of the class History are used to keep values in functions
00597     which take a lot of time during calculating, for instance in the 
00598     function Factorial(x)
00599 
00600     it means that when we're calculating e.g. Factorial(1000) and the 
00601     Factorial finds that we have calculated it before, the value (result)
00602     is taken from the history
00603 */
00604 template<class ValueType>
00605 class History 
00606 {
00607     /*!
00608         one item in the History's object holds a key, a value for the key
00609         and a corresponding error code
00610     */
00611     struct Item
00612     {
00613         ValueType key, value;
00614         ErrorCode  err;
00615     };
00616 
00617 
00618     /*!
00619         we use std::list for simply deleting the first item
00620         but because we're searching through the whole container
00621         (in the method Get) the container should not be too big
00622         (linear time of searching)
00623     */
00624     typedef std::list<Item> buffer_type;
00625     buffer_type buffer;
00626     typename buffer_type::size_type buffer_max_size;
00627 
00628 public:
00629     
00630     /*!
00631         default constructor
00632         default max size of the History's container is 15 items
00633     */
00634     History ()
00635     {
00636         buffer_max_size = 15;
00637     }
00638 
00639 
00640     /*!
00641         a constructor which takes another value of the max size
00642         of the History's container
00643     */
00644     History (typename buffer_type::size_type new_size)
00645     {
00646         buffer_max_size = new_size;
00647     }
00648 
00649 
00650     /*!
00651         this method adds one item into the History
00652         if the size of the container is greater than buffer_max_size
00653         the first item will be removed
00654     */
00655     void Add (const ValueType & key, const ValueType & value, ErrorCode  err)
00656     {
00657         Item item;
00658         item.key   = key;
00659         item.value = value;
00660         item.err   = err;
00661 
00662         buffer.insert( buffer.end(), item );
00663 
00664         if( buffer.size() > buffer_max_size )
00665             buffer.erase(buffer.begin());
00666     }
00667 
00668 
00669     /*!
00670         this method checks whether we have an item which has the key equal 'key'
00671 
00672         if there's such item the method sets the 'value' and the 'err'
00673         and returns true otherwise it returns false and 'value' and 'err'
00674         remain unchanged
00675     */
00676     bool Get (const ValueType & key, ValueType & value, ErrorCode  & err)
00677     {
00678         typename buffer_type::iterator i = buffer.begin();
00679 
00680         for( ; i != buffer.end() ; ++i )
00681         {
00682             if( i->key == key )
00683             {
00684                 value = i->value;
00685                 err   = i->err;
00686                 return true;
00687             }
00688         }
00689 
00690     return false;
00691     }
00692 
00693 
00694     /*!
00695         this methods deletes an item
00696 
00697         we assume that there is only one item with the 'key'
00698         (this methods removes the first one)
00699     */
00700     bool Remove (const ValueType & key)
00701     {
00702         typename buffer_type::iterator i = buffer.begin();
00703 
00704         for( ; i != buffer.end() ; ++i )
00705         {
00706             if( i->key == key )
00707             {
00708                 buffer.erase(i);
00709                 return true;
00710             }
00711         }
00712 
00713     return false;
00714     }
00715 
00716 
00717 }; // end of class History
00718 
00719 
00720 
00721 /*!
00722     this is an auxiliary class used when calculating Gamma() or Factorial()
00723 
00724     in multithreaded environment you can provide an object of this class to
00725     the Gamma() or Factorial() function, e.g;
00726         typedef Big<1, 3> MyBig;
00727         MyBig x = 123456;
00728         CGamma<MyBig> cgamma;
00729         std::cout << Gamma(x, cgamma);
00730     each thread should have its own CGamma<> object
00731 
00732     in a single-thread environment a CGamma<> object is a static variable
00733     in a second version of Gamma() and you don't have to explicitly use it, e.g.
00734         typedef Big<1, 3> MyBig;
00735         MyBig x = 123456;
00736         std::cout << Gamma(x);
00737 */
00738 template<class ValueType>
00739 struct CGamma 
00740 {
00741     /*!
00742         this table holds factorials
00743             1
00744             1
00745             2
00746             6
00747             24
00748             120
00749             720
00750             .......
00751     */
00752     std::vector<ValueType> fact ;
00753 
00754 
00755     /*!
00756         this table holds Bernoulli numbers
00757             1
00758             -0.5
00759             0.166666666666666666666666667
00760             0
00761             -0.0333333333333333333333333333
00762             0
00763             0.0238095238095238095238095238
00764             0
00765             -0.0333333333333333333333333333
00766             0
00767             0.075757575757575757575757576
00768             .....
00769     */
00770     std::vector<ValueType> bern ;
00771 
00772 
00773     /*!
00774         here we store some calculated values
00775         (this is for speeding up, if the next argument of Gamma() or Factorial()
00776         is in the 'history' then the result we are not calculating but simply
00777         return from the 'history' object)
00778     */
00779     History<ValueType>  history ;
00780 
00781 
00782     /*!
00783         this method prepares some coefficients: factorials and Bernoulli numbers
00784         stored in 'fact' and 'bern' objects
00785         
00786         how many values should be depends on the size of the mantissa - if
00787         the mantissa is larger then we must calculate more values
00788             for a mantissa which consists of 256 bits (8 words on a 32bit platform)
00789             we have to calculate about 30 values (the size of fact and bern will be 30),
00790             and for a 2048 bits mantissa we have to calculate 306 coefficients
00791 
00792         you don't have to call this method, these coefficients will be automatically calculated
00793         when they are needed
00794 
00795         you must note that calculating these coefficients is a little time-consuming operation,
00796         (especially when the mantissa is large) and first call to Gamma() or Factorial()
00797         can take more time than next calls, and in the end this is the point when InitAll()
00798         comes in handy: you can call this method somewhere at the beginning of your program
00799     */
00800     void InitAll ();
00801     // definition is in ttmath.h
00802 };
00803 
00804 
00805 
00806 
00807 } // namespace
00808 
00809 #endif
00810