ttmathobjects.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*
  2. * This file is a part of TTMath Mathematical Library
  3. * and is distributed under the (new) BSD licence.
  4. * Author: Tomasz Sowa <[email protected]>
  5. */
  6. /*
  7. * Copyright (c) 2006-2010, Tomasz Sowa
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * * Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. *
  16. * * Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. *
  20. * * Neither the name Tomasz Sowa nor the names of contributors to this
  21. * project may be used to endorse or promote products derived
  22. * from this software without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  25. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  28. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  30. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  31. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  32. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  33. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  34. * THE POSSIBILITY OF SUCH DAMAGE.
  35. */
  36. #ifndef headerfilettmathobject
  37. #define headerfilettmathobject
  38. /*!
  39. \file ttmathobjects.h
  40. \brief Mathematic functions.
  41. */
  42. #include <string>
  43. #include <vector>
  44. #include <list>
  45. #include <map>
  46. #include "ttmathtypes.h"
  47. #include "ttmathmisc.h"
  48. namespace ttmath
  49. {
  50. /*!
  51. objects of this class are used with the mathematical parser
  52. they hold variables or functions defined by a user
  53. each object has its own table in which we're keeping variables or functions
  54. */
  55. class Objects
  56. {
  57. public:
  58. /*!
  59. one item (variable or function)
  60. 'items' will be on the table
  61. */
  62. struct Item
  63. {
  64. // name of a variable of a function
  65. // internally we store variables and funcions as std::string (not std::wstring even when wide characters are used)
  66. std::string value;
  67. // number of parameters required by the function
  68. // (if there's a variable this 'param' is ignored)
  69. int param;
  70. Item() {}
  71. Item(const std::string & v, int p) : value(v), param(p) {}
  72. };
  73. // 'Table' is the type of our table
  74. typedef std::map<std::string, Item> Table;
  75. typedef Table::iterator Iterator;
  76. typedef Table::const_iterator CIterator;
  77. /*!
  78. this method returns true if a character 'c' is a character
  79. which can be in a name
  80. if 'can_be_digit' is true that means when the 'c' is a digit this
  81. method returns true otherwise it returns false
  82. */
  83. static bool CorrectCharacter(int c, bool can_be_digit)
  84. {
  85. if( (c>='a' && c<='z') || (c>='A' && c<='Z') )
  86. return true;
  87. if( can_be_digit && ((c>='0' && c<='9') || c=='_') )
  88. return true;
  89. return false;
  90. }
  91. /*!
  92. this method returns true if the name can be as a name of an object
  93. */
  94. template<class string_type>
  95. static bool IsNameCorrect(const string_type & name)
  96. {
  97. if( name.empty() )
  98. return false;
  99. if( !CorrectCharacter(name[0], false) )
  100. return false;
  101. typename string_type::const_iterator i = name.begin();
  102. for(++i ; i!=name.end() ; ++i)
  103. if( !CorrectCharacter(*i, true) )
  104. return false;
  105. return true;
  106. }
  107. /*!
  108. this method returns true if such an object is defined (name exists)
  109. */
  110. bool IsDefined(const std::string & name)
  111. {
  112. Iterator i = table.find(name);
  113. if( i != table.end() )
  114. // we have this object in our table
  115. return true;
  116. return false;
  117. }
  118. #ifndef TTMATH_DONT_USE_WCHAR
  119. /*!
  120. this method returns true if such an object is defined (name exists)
  121. */
  122. bool IsDefined(const std::wstring & name)
  123. {
  124. // we should check whether the name (in wide characters) are correct
  125. // before calling AssignString() function
  126. if( !IsNameCorrect(name) )
  127. return false;
  128. Misc::AssignString(str_tmp1, name);
  129. return IsDefined(str_tmp1);
  130. }
  131. #endif
  132. /*!
  133. this method adds one object (variable of function) into the table
  134. */
  135. ErrorCode Add(const std::string & name, const std::string & value, int param = 0)
  136. {
  137. if( !IsNameCorrect(name) )
  138. return err_incorrect_name;
  139. Iterator i = table.find(name);
  140. if( i != table.end() )
  141. // we have this object in our table
  142. return err_object_exists;
  143. table.insert( std::make_pair(name, Item(value, param)) );
  144. return err_ok;
  145. }
  146. #ifndef TTMATH_DONT_USE_WCHAR
  147. /*!
  148. this method adds one object (variable of function) into the table
  149. */
  150. ErrorCode Add(const std::wstring & name, const std::wstring & value, int param = 0)
  151. {
  152. // we should check whether the name (in wide characters) are correct
  153. // before calling AssignString() function
  154. if( !IsNameCorrect(name) )
  155. return err_incorrect_name;
  156. Misc::AssignString(str_tmp1, name);
  157. Misc::AssignString(str_tmp2, value);
  158. return Add(str_tmp1, str_tmp2, param);
  159. }
  160. #endif
  161. /*!
  162. this method returns 'true' if the table is empty
  163. */
  164. bool Empty() const
  165. {
  166. return table.empty();
  167. }
  168. /*!
  169. this method clears the table
  170. */
  171. void Clear()
  172. {
  173. return table.clear();
  174. }
  175. /*!
  176. this method returns 'const_iterator' on the first item on the table
  177. */
  178. CIterator Begin() const
  179. {
  180. return table.begin();
  181. }
  182. /*!
  183. this method returns 'const_iterator' pointing at the space after last item
  184. (returns table.end())
  185. */
  186. CIterator End() const
  187. {
  188. return table.end();
  189. }
  190. /*!
  191. this method changes the value and the number of parameters for a specific object
  192. */
  193. ErrorCode EditValue(const std::string & name, const std::string & value, int param = 0)
  194. {
  195. if( !IsNameCorrect(name) )
  196. return err_incorrect_name;
  197. Iterator i = table.find(name);
  198. if( i == table.end() )
  199. return err_unknown_object;
  200. i->second.value = value;
  201. i->second.param = param;
  202. return err_ok;
  203. }
  204. #ifndef TTMATH_DONT_USE_WCHAR
  205. /*!
  206. this method changes the value and the number of parameters for a specific object
  207. */
  208. ErrorCode EditValue(const std::wstring & name, const std::wstring & value, int param = 0)
  209. {
  210. // we should check whether the name (in wide characters) are correct
  211. // before calling AssignString() function
  212. if( !IsNameCorrect(name) )
  213. return err_incorrect_name;
  214. Misc::AssignString(str_tmp1, name);
  215. Misc::AssignString(str_tmp2, value);
  216. return EditValue(str_tmp1, str_tmp2, param);
  217. }
  218. #endif
  219. /*!
  220. this method changes the name of a specific object
  221. */
  222. ErrorCode EditName(const std::string & old_name, const std::string & new_name)
  223. {
  224. if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) )
  225. return err_incorrect_name;
  226. Iterator old_i = table.find(old_name);
  227. if( old_i == table.end() )
  228. return err_unknown_object;
  229. if( old_name == new_name )
  230. // the new name is the same as the old one
  231. // we treat it as a normal situation
  232. return err_ok;
  233. ErrorCode err = Add(new_name, old_i->second.value, old_i->second.param);
  234. if( err == err_ok )
  235. {
  236. old_i = table.find(old_name);
  237. TTMATH_ASSERT( old_i != table.end() )
  238. table.erase(old_i);
  239. }
  240. return err;
  241. }
  242. #ifndef TTMATH_DONT_USE_WCHAR
  243. /*!
  244. this method changes the name of a specific object
  245. */
  246. ErrorCode EditName(const std::wstring & old_name, const std::wstring & new_name)
  247. {
  248. // we should check whether the name (in wide characters) are correct
  249. // before calling AssignString() function
  250. if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) )
  251. return err_incorrect_name;
  252. Misc::AssignString(str_tmp1, old_name);
  253. Misc::AssignString(str_tmp2, new_name);
  254. return EditName(str_tmp1, str_tmp2);
  255. }
  256. #endif
  257. /*!
  258. this method deletes an object
  259. */
  260. ErrorCode Delete(const std::string & name)
  261. {
  262. if( !IsNameCorrect(name) )
  263. return err_incorrect_name;
  264. Iterator i = table.find(name);
  265. if( i == table.end() )
  266. return err_unknown_object;
  267. table.erase( i );
  268. return err_ok;
  269. }
  270. #ifndef TTMATH_DONT_USE_WCHAR
  271. /*!
  272. this method deletes an object
  273. */
  274. ErrorCode Delete(const std::wstring & name)
  275. {
  276. // we should check whether the name (in wide characters) are correct
  277. // before calling AssignString() function
  278. if( !IsNameCorrect(name) )
  279. return err_incorrect_name;
  280. Misc::AssignString(str_tmp1, name);
  281. return Delete(str_tmp1);
  282. }
  283. #endif
  284. /*!
  285. this method gets the value of a specific object
  286. */
  287. ErrorCode GetValue(const std::string & name, std::string & value) const
  288. {
  289. if( !IsNameCorrect(name) )
  290. return err_incorrect_name;
  291. CIterator i = table.find(name);
  292. if( i == table.end() )
  293. {
  294. value.clear();
  295. return err_unknown_object;
  296. }
  297. value = i->second.value;
  298. return err_ok;
  299. }
  300. #ifndef TTMATH_DONT_USE_WCHAR
  301. /*!
  302. this method gets the value of a specific object
  303. */
  304. ErrorCode GetValue(const std::wstring & name, std::wstring & value)
  305. {
  306. // we should check whether the name (in wide characters) are correct
  307. // before calling AssignString() function
  308. if( !IsNameCorrect(name) )
  309. return err_incorrect_name;
  310. Misc::AssignString(str_tmp1, name);
  311. ErrorCode err = GetValue(str_tmp1, str_tmp2);
  312. Misc::AssignString(value, str_tmp2);
  313. return err;
  314. }
  315. #endif
  316. /*!
  317. this method gets the value of a specific object
  318. (this version is used for not copying the whole string)
  319. */
  320. ErrorCode GetValue(const std::string & name, const char ** value) const
  321. {
  322. if( !IsNameCorrect(name) )
  323. return err_incorrect_name;
  324. CIterator i = table.find(name);
  325. if( i == table.end() )
  326. {
  327. *value = 0;
  328. return err_unknown_object;
  329. }
  330. *value = i->second.value.c_str();
  331. return err_ok;
  332. }
  333. #ifndef TTMATH_DONT_USE_WCHAR
  334. /*!
  335. this method gets the value of a specific object
  336. (this version is used for not copying the whole string)
  337. */
  338. ErrorCode GetValue(const std::wstring & name, const char ** value)
  339. {
  340. // we should check whether the name (in wide characters) are correct
  341. // before calling AssignString() function
  342. if( !IsNameCorrect(name) )
  343. return err_incorrect_name;
  344. Misc::AssignString(str_tmp1, name);
  345. return GetValue(str_tmp1, value);
  346. }
  347. #endif
  348. /*!
  349. this method gets the value and the number of parameters
  350. of a specific object
  351. */
  352. ErrorCode GetValueAndParam(const std::string & name, std::string & value, int * param) const
  353. {
  354. if( !IsNameCorrect(name) )
  355. return err_incorrect_name;
  356. CIterator i = table.find(name);
  357. if( i == table.end() )
  358. {
  359. value.empty();
  360. *param = 0;
  361. return err_unknown_object;
  362. }
  363. value = i->second.value;
  364. *param = i->second.param;
  365. return err_ok;
  366. }
  367. #ifndef TTMATH_DONT_USE_WCHAR
  368. /*!
  369. this method gets the value and the number of parameters
  370. of a specific object
  371. */
  372. ErrorCode GetValueAndParam(const std::wstring & name, std::wstring & value, int * param)
  373. {
  374. // we should check whether the name (in wide characters) are correct
  375. // before calling AssignString() function
  376. if( !IsNameCorrect(name) )
  377. return err_incorrect_name;
  378. Misc::AssignString(str_tmp1, name);
  379. ErrorCode err = GetValueAndParam(str_tmp1, str_tmp2, param);
  380. Misc::AssignString(value, str_tmp2);
  381. return err;
  382. }
  383. #endif
  384. /*!
  385. this method sets the value and the number of parameters
  386. of a specific object
  387. (this version is used for not copying the whole string)
  388. */
  389. ErrorCode GetValueAndParam(const std::string & name, const char ** value, int * param) const
  390. {
  391. if( !IsNameCorrect(name) )
  392. return err_incorrect_name;
  393. CIterator i = table.find(name);
  394. if( i == table.end() )
  395. {
  396. *value = 0;
  397. *param = 0;
  398. return err_unknown_object;
  399. }
  400. *value = i->second.value.c_str();
  401. *param = i->second.param;
  402. return err_ok;
  403. }
  404. #ifndef TTMATH_DONT_USE_WCHAR
  405. /*!
  406. this method sets the value and the number of parameters
  407. of a specific object
  408. (this version is used for not copying the whole string
  409. but in fact we make one copying during AssignString())
  410. */
  411. ErrorCode GetValueAndParam(const std::wstring & name, const char ** value, int * param)
  412. {
  413. // we should check whether the name (in wide characters) are correct
  414. // before calling AssignString() function
  415. if( !IsNameCorrect(name) )
  416. return err_incorrect_name;
  417. Misc::AssignString(str_tmp1, name);
  418. return GetValueAndParam(str_tmp1, value, param);
  419. }
  420. #endif
  421. /*!
  422. this method returns a pointer into the table
  423. */
  424. Table * GetTable()
  425. {
  426. return &table;
  427. }
  428. private:
  429. Table table;
  430. std::string str_tmp1, str_tmp2;
  431. }; // end of class Objects
  432. /*!
  433. objects of the class History are used to keep values in functions
  434. which take a lot of time during calculating, for instance in the
  435. function Factorial(x)
  436. it means that when we're calculating e.g. Factorial(1000) and the
  437. Factorial finds that we have calculated it before, the value (result)
  438. is taken from the history
  439. */
  440. template<class ValueType>
  441. class History
  442. {
  443. /*!
  444. one item in the History's object holds a key, a value for the key
  445. and a corresponding error code
  446. */
  447. struct Item
  448. {
  449. ValueType key, value;
  450. ErrorCode err;
  451. };
  452. /*!
  453. we use std::list for simply deleting the first item
  454. but because we're searching through the whole container
  455. (in the method Get) the container should not be too big
  456. (linear time of searching)
  457. */
  458. typedef std::list<Item> buffer_type;
  459. buffer_type buffer;
  460. typename buffer_type::size_type buffer_max_size;
  461. public:
  462. /*!
  463. default constructor
  464. default max size of the History's container is 15 items
  465. */
  466. History()
  467. {
  468. buffer_max_size = 15;
  469. }
  470. /*!
  471. a constructor which takes another value of the max size
  472. of the History's container
  473. */
  474. History(typename buffer_type::size_type new_size)
  475. {
  476. buffer_max_size = new_size;
  477. }
  478. /*!
  479. this method adds one item into the History
  480. if the size of the container is greater than buffer_max_size
  481. the first item will be removed
  482. */
  483. void Add(const ValueType & key, const ValueType & value, ErrorCode err)
  484. {
  485. Item item;
  486. item.key = key;
  487. item.value = value;
  488. item.err = err;
  489. buffer.insert( buffer.end(), item );
  490. if( buffer.size() > buffer_max_size )
  491. buffer.erase(buffer.begin());
  492. }
  493. /*!
  494. this method checks whether we have an item which has the key equal 'key'
  495. if there's such item the method sets the 'value' and the 'err'
  496. and returns true otherwise it returns false and 'value' and 'err'
  497. remain unchanged
  498. */
  499. bool Get(const ValueType & key, ValueType & value, ErrorCode & err)
  500. {
  501. typename buffer_type::iterator i = buffer.begin();
  502. for( ; i != buffer.end() ; ++i )
  503. {
  504. if( i->key == key )
  505. {
  506. value = i->value;
  507. err = i->err;
  508. return true;
  509. }
  510. }
  511. return false;
  512. }
  513. /*!
  514. this methods deletes an item
  515. we assume that there is only one item with the 'key'
  516. (this methods removes the first one)
  517. */
  518. bool Remove(const ValueType & key)
  519. {
  520. typename buffer_type::iterator i = buffer.begin();
  521. for( ; i != buffer.end() ; ++i )
  522. {
  523. if( i->key == key )
  524. {
  525. buffer.erase(i);
  526. return true;
  527. }
  528. }
  529. return false;
  530. }
  531. }; // end of class History
  532. /*!
  533. this is an auxiliary class used when calculating Gamma() or Factorial()
  534. in multithreaded environment you can provide an object of this class to
  535. the Gamma() or Factorial() function, e.g;
  536. typedef Big<1, 3> MyBig;
  537. MyBig x = 123456;
  538. CGamma<MyBig> cgamma;
  539. std::cout << Gamma(x, cgamma);
  540. each thread should have its own CGamma<> object
  541. in a single-thread environment a CGamma<> object is a static variable
  542. in a second version of Gamma() and you don't have to explicitly use it, e.g.
  543. typedef Big<1, 3> MyBig;
  544. MyBig x = 123456;
  545. std::cout << Gamma(x);
  546. */
  547. template<class ValueType>
  548. struct CGamma
  549. {
  550. /*!
  551. this table holds factorials
  552. 1
  553. 1
  554. 2
  555. 6
  556. 24
  557. 120
  558. 720
  559. .......
  560. */
  561. std::vector<ValueType> fact;
  562. /*!
  563. this table holds Bernoulli numbers
  564. 1
  565. -0.5
  566. 0.166666666666666666666666667
  567. 0
  568. -0.0333333333333333333333333333
  569. 0
  570. 0.0238095238095238095238095238
  571. 0
  572. -0.0333333333333333333333333333
  573. 0
  574. 0.075757575757575757575757576
  575. .....
  576. */
  577. std::vector<ValueType> bern;
  578. /*!
  579. here we store some calculated values
  580. (this is for speeding up, if the next argument of Gamma() or Factorial()
  581. is in the 'history' then the result we are not calculating but simply
  582. return from the 'history' object)
  583. */
  584. History<ValueType> history;
  585. /*!
  586. this method prepares some coefficients: factorials and Bernoulli numbers
  587. stored in 'fact' and 'bern' objects
  588. how many values should be depends on the size of the mantissa - if
  589. the mantissa is larger then we must calculate more values
  590. for a mantissa which consists of 256 bits (8 words on a 32bit platform)
  591. we have to calculate about 30 values (the size of fact and bern will be 30),
  592. and for a 2048 bits mantissa we have to calculate 306 coefficients
  593. you don't have to call this method, these coefficients will be automatically calculated
  594. when they are needed
  595. you must note that calculating these coefficients is a little time-consuming operation,
  596. (especially when the mantissa is large) and first call to Gamma() or Factorial()
  597. can take more time than next calls, and in the end this is the point when InitAll()
  598. comes in handy: you can call this method somewhere at the beginning of your program
  599. */
  600. void InitAll();
  601. // definition is in ttmath.h
  602. };
  603. } // namespace
  604. #endif