/include/fparser/mpfr/GmpInt.cc

https://github.com/nilsvandensteen/coolfluid3 · C++ · 710 lines · 588 code · 92 blank · 30 comment · 51 complexity · b4ad5f42a8bdd8efe87483e3b8041f6a MD5 · raw file

  1. #include "GmpInt.hh"
  2. #include <gmp.h>
  3. #include <deque>
  4. #include <vector>
  5. #include <cstring>
  6. #include <cctype>
  7. //===========================================================================
  8. // Shared data
  9. //===========================================================================
  10. namespace
  11. {
  12. unsigned long gIntDefaultNumberOfBits = 256;
  13. std::vector<char>& intString()
  14. {
  15. static std::vector<char> str;
  16. return str;
  17. }
  18. }
  19. //===========================================================================
  20. // Auxiliary structs
  21. //===========================================================================
  22. struct GmpInt::GmpIntData
  23. {
  24. unsigned mRefCount;
  25. GmpIntData* nextFreeNode;
  26. mpz_t mInteger;
  27. GmpIntData(): mRefCount(1), nextFreeNode(0) {}
  28. };
  29. class GmpInt::GmpIntDataContainer
  30. {
  31. std::deque<GmpInt::GmpIntData> mData;
  32. GmpInt::GmpIntData* mFirstFreeNode;
  33. GmpInt::GmpIntData* mConst_0;
  34. public:
  35. GmpIntDataContainer(): mFirstFreeNode(0), mConst_0(0) {}
  36. ~GmpIntDataContainer()
  37. {
  38. for(size_t i = 0; i < mData.size(); ++i)
  39. mpz_clear(mData[i].mInteger);
  40. }
  41. GmpInt::GmpIntData* allocateGmpIntData(unsigned long numberOfBits,
  42. bool initToZero)
  43. {
  44. if(mFirstFreeNode)
  45. {
  46. GmpInt::GmpIntData* node = mFirstFreeNode;
  47. mFirstFreeNode = node->nextFreeNode;
  48. if(initToZero) mpz_set_si(node->mInteger, 0);
  49. ++(node->mRefCount);
  50. return node;
  51. }
  52. mData.push_back(GmpInt::GmpIntData());
  53. if(numberOfBits > 0)
  54. mpz_init2(mData.back().mInteger, numberOfBits);
  55. else
  56. mpz_init(mData.back().mInteger);
  57. return &mData.back();
  58. }
  59. void releaseGmpIntData(GmpIntData* data)
  60. {
  61. if(--(data->mRefCount) == 0)
  62. {
  63. data->nextFreeNode = mFirstFreeNode;
  64. mFirstFreeNode = data;
  65. }
  66. }
  67. GmpInt::GmpIntData* const_0()
  68. {
  69. if(!mConst_0)
  70. mConst_0 = allocateGmpIntData(gIntDefaultNumberOfBits, true);
  71. return mConst_0;
  72. }
  73. };
  74. GmpInt::GmpIntDataContainer& GmpInt::gmpIntDataContainer()
  75. {
  76. static GmpIntDataContainer container;
  77. return container;
  78. }
  79. //===========================================================================
  80. // Auxiliary functions
  81. //===========================================================================
  82. void GmpInt::setDefaultNumberOfBits(unsigned long value)
  83. {
  84. gIntDefaultNumberOfBits = value;
  85. }
  86. unsigned long GmpInt::getDefaultNumberOfBits()
  87. {
  88. return gIntDefaultNumberOfBits;
  89. }
  90. inline void GmpInt::copyIfShared()
  91. {
  92. if(mData->mRefCount > 1)
  93. {
  94. --(mData->mRefCount);
  95. GmpIntData* oldData = mData;
  96. mData = gmpIntDataContainer().allocateGmpIntData(0, false);
  97. mpz_set(mData->mInteger, oldData->mInteger);
  98. }
  99. }
  100. //===========================================================================
  101. // Constructors, destructor, assignment
  102. //===========================================================================
  103. GmpInt::GmpInt(DummyType):
  104. mData(gmpIntDataContainer().allocateGmpIntData(0, false))
  105. {}
  106. GmpInt::GmpInt()
  107. {
  108. mData = gmpIntDataContainer().const_0();
  109. ++(mData->mRefCount);
  110. }
  111. GmpInt::GmpInt(long value)
  112. {
  113. if(value == 0)
  114. {
  115. mData = gmpIntDataContainer().const_0();
  116. ++(mData->mRefCount);
  117. }
  118. else
  119. {
  120. mData = gmpIntDataContainer().allocateGmpIntData
  121. (gIntDefaultNumberOfBits, false);
  122. mpz_set_si(mData->mInteger, value);
  123. }
  124. }
  125. GmpInt::GmpInt(unsigned long value)
  126. {
  127. if(value == 0)
  128. {
  129. mData = gmpIntDataContainer().const_0();
  130. ++(mData->mRefCount);
  131. }
  132. else
  133. {
  134. mData = gmpIntDataContainer().allocateGmpIntData
  135. (gIntDefaultNumberOfBits, false);
  136. mpz_set_ui(mData->mInteger, value);
  137. }
  138. }
  139. GmpInt::GmpInt(int value)
  140. {
  141. if(value == 0)
  142. {
  143. mData = gmpIntDataContainer().const_0();
  144. ++(mData->mRefCount);
  145. }
  146. else
  147. {
  148. mData = gmpIntDataContainer().allocateGmpIntData
  149. (gIntDefaultNumberOfBits, false);
  150. mpz_set_si(mData->mInteger, value);
  151. }
  152. }
  153. GmpInt::GmpInt(double value)
  154. {
  155. const double absValue = value >= 0.0 ? value : -value;
  156. if(absValue < 1.0)
  157. {
  158. mData = gmpIntDataContainer().const_0();
  159. ++(mData->mRefCount);
  160. }
  161. else
  162. {
  163. mData = gmpIntDataContainer().allocateGmpIntData
  164. (gIntDefaultNumberOfBits, false);
  165. mpz_set_d(mData->mInteger, value);
  166. }
  167. }
  168. GmpInt::GmpInt(long double value)
  169. {
  170. const long double absValue = value >= 0.0L ? value : -value;
  171. if(absValue < 1.0L)
  172. {
  173. mData = gmpIntDataContainer().const_0();
  174. ++(mData->mRefCount);
  175. }
  176. else
  177. {
  178. mData = gmpIntDataContainer().allocateGmpIntData
  179. (gIntDefaultNumberOfBits, false);
  180. mpz_set_d(mData->mInteger, double(value));
  181. }
  182. }
  183. GmpInt::GmpInt(const GmpInt& rhs):
  184. mData(rhs.mData)
  185. {
  186. ++(mData->mRefCount);
  187. }
  188. GmpInt& GmpInt::operator=(const GmpInt& rhs)
  189. {
  190. if(mData != rhs.mData)
  191. {
  192. gmpIntDataContainer().releaseGmpIntData(mData);
  193. mData = rhs.mData;
  194. ++(mData->mRefCount);
  195. }
  196. return *this;
  197. }
  198. GmpInt& GmpInt::operator=(signed long value)
  199. {
  200. if(value == 0)
  201. {
  202. gmpIntDataContainer().releaseGmpIntData(mData);
  203. mData = gmpIntDataContainer().const_0();
  204. ++(mData->mRefCount);
  205. }
  206. else
  207. {
  208. if(mData->mRefCount > 1)
  209. {
  210. --(mData->mRefCount);
  211. mData = gmpIntDataContainer().allocateGmpIntData
  212. (gIntDefaultNumberOfBits, false);
  213. }
  214. mpz_set_si(mData->mInteger, value);
  215. }
  216. return *this;
  217. }
  218. GmpInt::~GmpInt()
  219. {
  220. gmpIntDataContainer().releaseGmpIntData(mData);
  221. }
  222. //===========================================================================
  223. // Data getters
  224. //===========================================================================
  225. template<>
  226. void GmpInt::get_raw_mpfr_data<mpz_t>(mpz_t& dest_mpz_t)
  227. {
  228. std::memcpy(&dest_mpz_t, mData->mInteger, sizeof(mpz_t));
  229. }
  230. const char* GmpInt::getAsString(int base) const
  231. {
  232. intString().resize(mpz_sizeinbase(mData->mInteger, base) + 2);
  233. return mpz_get_str(&intString()[0], base, mData->mInteger);
  234. }
  235. long GmpInt::toInt() const
  236. {
  237. return mpz_get_si(mData->mInteger);
  238. }
  239. //===========================================================================
  240. // Modifying operators
  241. //===========================================================================
  242. GmpInt& GmpInt::operator+=(const GmpInt& rhs)
  243. {
  244. copyIfShared();
  245. mpz_add(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  246. return *this;
  247. }
  248. GmpInt& GmpInt::operator+=(long value)
  249. {
  250. copyIfShared();
  251. if(value >= 0)
  252. mpz_add_ui(mData->mInteger, mData->mInteger, value);
  253. else
  254. mpz_sub_ui(mData->mInteger, mData->mInteger, -value);
  255. return *this;
  256. }
  257. GmpInt& GmpInt::operator-=(const GmpInt& rhs)
  258. {
  259. copyIfShared();
  260. mpz_sub(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  261. return *this;
  262. }
  263. GmpInt& GmpInt::operator-=(long value)
  264. {
  265. copyIfShared();
  266. if(value >= 0)
  267. mpz_sub_ui(mData->mInteger, mData->mInteger, value);
  268. else
  269. mpz_add_ui(mData->mInteger, mData->mInteger, -value);
  270. return *this;
  271. }
  272. GmpInt& GmpInt::operator*=(const GmpInt& rhs)
  273. {
  274. copyIfShared();
  275. mpz_mul(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  276. return *this;
  277. }
  278. GmpInt& GmpInt::operator*=(long value)
  279. {
  280. copyIfShared();
  281. mpz_mul_si(mData->mInteger, mData->mInteger, value);
  282. return *this;
  283. }
  284. GmpInt& GmpInt::operator/=(const GmpInt& rhs)
  285. {
  286. copyIfShared();
  287. mpz_tdiv_q(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  288. return *this;
  289. }
  290. GmpInt& GmpInt::operator/=(long value)
  291. {
  292. copyIfShared();
  293. if(value >= 0)
  294. mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, value);
  295. else
  296. {
  297. mpz_neg(mData->mInteger, mData->mInteger);
  298. mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, -value);
  299. }
  300. return *this;
  301. }
  302. GmpInt& GmpInt::operator%=(const GmpInt& rhs)
  303. {
  304. copyIfShared();
  305. if(operator<(0))
  306. {
  307. negate();
  308. mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  309. negate();
  310. }
  311. else
  312. {
  313. mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  314. }
  315. return *this;
  316. }
  317. GmpInt& GmpInt::operator%=(long value)
  318. {
  319. copyIfShared();
  320. if(value < 0) value = -value;
  321. if(operator<(0))
  322. {
  323. negate();
  324. mpz_mod_ui(mData->mInteger, mData->mInteger, value);
  325. negate();
  326. }
  327. else
  328. {
  329. mpz_mod_ui(mData->mInteger, mData->mInteger, value);
  330. }
  331. return *this;
  332. }
  333. GmpInt& GmpInt::operator<<=(unsigned long bits)
  334. {
  335. copyIfShared();
  336. mpz_mul_2exp(mData->mInteger, mData->mInteger, bits);
  337. return *this;
  338. }
  339. GmpInt& GmpInt::operator>>=(unsigned long bits)
  340. {
  341. copyIfShared();
  342. mpz_tdiv_q_2exp(mData->mInteger, mData->mInteger, bits);
  343. return *this;
  344. }
  345. //===========================================================================
  346. // Modifying functions
  347. //===========================================================================
  348. void GmpInt::addProduct(const GmpInt& value1, const GmpInt& value2)
  349. {
  350. copyIfShared();
  351. mpz_addmul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger);
  352. }
  353. void GmpInt::addProduct(const GmpInt& value1, unsigned long value2)
  354. {
  355. copyIfShared();
  356. mpz_addmul_ui(mData->mInteger, value1.mData->mInteger, value2);
  357. }
  358. void GmpInt::subProduct(const GmpInt& value1, const GmpInt& value2)
  359. {
  360. copyIfShared();
  361. mpz_submul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger);
  362. }
  363. void GmpInt::subProduct(const GmpInt& value1, unsigned long value2)
  364. {
  365. copyIfShared();
  366. mpz_submul_ui(mData->mInteger, value1.mData->mInteger, value2);
  367. }
  368. void GmpInt::negate()
  369. {
  370. copyIfShared();
  371. mpz_neg(mData->mInteger, mData->mInteger);
  372. }
  373. void GmpInt::abs()
  374. {
  375. copyIfShared();
  376. mpz_abs(mData->mInteger, mData->mInteger);
  377. }
  378. GmpInt GmpInt::abs(const GmpInt& value)
  379. {
  380. GmpInt retval(kNoInitialization);
  381. mpz_abs(retval.mData->mInteger, value.mData->mInteger);
  382. return retval;
  383. }
  384. //===========================================================================
  385. // Non-modifying operators
  386. //===========================================================================
  387. GmpInt GmpInt::operator+(const GmpInt& rhs) const
  388. {
  389. GmpInt retval(kNoInitialization);
  390. mpz_add(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  391. return retval;
  392. }
  393. GmpInt GmpInt::operator+(long value) const
  394. {
  395. GmpInt retval(kNoInitialization);
  396. if(value >= 0)
  397. mpz_add_ui(retval.mData->mInteger, mData->mInteger, value);
  398. else
  399. mpz_sub_ui(retval.mData->mInteger, mData->mInteger, -value);
  400. return retval;
  401. }
  402. GmpInt GmpInt::operator-(const GmpInt& rhs) const
  403. {
  404. GmpInt retval(kNoInitialization);
  405. mpz_sub(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  406. return retval;
  407. }
  408. GmpInt GmpInt::operator-(long value) const
  409. {
  410. GmpInt retval(kNoInitialization);
  411. if(value >= 0)
  412. mpz_sub_ui(retval.mData->mInteger, mData->mInteger, value);
  413. else
  414. mpz_add_ui(retval.mData->mInteger, mData->mInteger, -value);
  415. return retval;
  416. }
  417. GmpInt GmpInt::operator*(const GmpInt& rhs) const
  418. {
  419. GmpInt retval(kNoInitialization);
  420. mpz_mul(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  421. return retval;
  422. }
  423. GmpInt GmpInt::operator*(long value) const
  424. {
  425. GmpInt retval(kNoInitialization);
  426. mpz_mul_si(retval.mData->mInteger, mData->mInteger, value);
  427. return retval;
  428. }
  429. GmpInt GmpInt::operator/(const GmpInt& rhs) const
  430. {
  431. GmpInt retval(kNoInitialization);
  432. mpz_tdiv_q(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  433. return retval;
  434. }
  435. GmpInt GmpInt::operator/(long value) const
  436. {
  437. GmpInt retval(kNoInitialization);
  438. if(value >= 0)
  439. mpz_tdiv_q_ui(retval.mData->mInteger, mData->mInteger, value);
  440. else
  441. {
  442. mpz_neg(retval.mData->mInteger, mData->mInteger);
  443. mpz_tdiv_q_ui(retval.mData->mInteger, retval.mData->mInteger, -value);
  444. }
  445. return retval;
  446. }
  447. GmpInt GmpInt::operator%(const GmpInt& rhs) const
  448. {
  449. GmpInt retval(kNoInitialization);
  450. if(operator<(0))
  451. {
  452. mpz_neg(retval.mData->mInteger, mData->mInteger);
  453. mpz_mod(retval.mData->mInteger,
  454. retval.mData->mInteger, rhs.mData->mInteger);
  455. retval.negate();
  456. }
  457. else
  458. {
  459. mpz_mod(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
  460. }
  461. return retval;
  462. }
  463. GmpInt GmpInt::operator%(long value) const
  464. {
  465. GmpInt retval(kNoInitialization);
  466. if(value < 0) value = -value;
  467. if(operator<(0))
  468. {
  469. mpz_neg(retval.mData->mInteger, mData->mInteger);
  470. mpz_mod_ui(retval.mData->mInteger, retval.mData->mInteger, value);
  471. retval.negate();
  472. }
  473. else
  474. {
  475. mpz_mod_ui(retval.mData->mInteger, mData->mInteger, value);
  476. }
  477. return retval;
  478. }
  479. GmpInt GmpInt::operator-() const
  480. {
  481. GmpInt retval(kNoInitialization);
  482. mpz_neg(retval.mData->mInteger, mData->mInteger);
  483. return retval;
  484. }
  485. GmpInt GmpInt::operator<<(unsigned long bits) const
  486. {
  487. GmpInt retval(kNoInitialization);
  488. mpz_mul_2exp(retval.mData->mInteger, mData->mInteger, bits);
  489. return retval;
  490. }
  491. GmpInt GmpInt::operator>>(unsigned long bits) const
  492. {
  493. GmpInt retval(kNoInitialization);
  494. mpz_tdiv_q_2exp(retval.mData->mInteger, mData->mInteger, bits);
  495. return retval;
  496. }
  497. //===========================================================================
  498. // Comparison operators
  499. //===========================================================================
  500. bool GmpInt::operator<(const GmpInt& rhs) const
  501. {
  502. return mpz_cmp(mData->mInteger, rhs.mData->mInteger) < 0;
  503. }
  504. bool GmpInt::operator<(long value) const
  505. {
  506. return mpz_cmp_si(mData->mInteger, value) < 0;
  507. }
  508. bool GmpInt::operator<=(const GmpInt& rhs) const
  509. {
  510. return mpz_cmp(mData->mInteger, rhs.mData->mInteger) <= 0;
  511. }
  512. bool GmpInt::operator<=(long value) const
  513. {
  514. return mpz_cmp_si(mData->mInteger, value) <= 0;
  515. }
  516. bool GmpInt::operator>(const GmpInt& rhs) const
  517. {
  518. return mpz_cmp(mData->mInteger, rhs.mData->mInteger) > 0;
  519. }
  520. bool GmpInt::operator>(long value) const
  521. {
  522. return mpz_cmp_si(mData->mInteger, value) > 0;
  523. }
  524. bool GmpInt::operator>=(const GmpInt& rhs) const
  525. {
  526. return mpz_cmp(mData->mInteger, rhs.mData->mInteger) >= 0;
  527. }
  528. bool GmpInt::operator>=(long value) const
  529. {
  530. return mpz_cmp_si(mData->mInteger, value) >= 0;
  531. }
  532. bool GmpInt::operator==(const GmpInt& rhs) const
  533. {
  534. return mpz_cmp(mData->mInteger, rhs.mData->mInteger) == 0;
  535. }
  536. bool GmpInt::operator==(long value) const
  537. {
  538. return mpz_cmp_si(mData->mInteger, value) == 0;
  539. }
  540. bool GmpInt::operator!=(const GmpInt& rhs) const
  541. {
  542. return mpz_cmp(mData->mInteger, rhs.mData->mInteger) != 0;
  543. }
  544. bool GmpInt::operator!=(long value) const
  545. {
  546. return mpz_cmp_si(mData->mInteger, value) != 0;
  547. }
  548. void GmpInt::parseValue(const char* value)
  549. {
  550. mpz_set_str(mData->mInteger, value, 10);
  551. }
  552. void GmpInt::parseValue(const char* value, char** endptr)
  553. {
  554. static std::vector<char> str;
  555. unsigned startIndex = 0;
  556. while(value[startIndex] && std::isspace(value[startIndex])) ++startIndex;
  557. if(!value[startIndex]) { *endptr = const_cast<char*>(value); return; }
  558. unsigned endIndex = startIndex;
  559. if(value[endIndex] == '-') ++endIndex;
  560. if(!std::isdigit(value[endIndex]))
  561. { *endptr = const_cast<char*>(value); return; }
  562. if(value[endIndex] == '0' && value[endIndex+1] == 'x')
  563. {
  564. endIndex += 1;
  565. while(std::isxdigit(value[++endIndex])) {}
  566. }
  567. else
  568. {
  569. while(std::isdigit(value[++endIndex])) {}
  570. }
  571. str.reserve(endIndex - startIndex + 1);
  572. str.assign(value + startIndex, value + endIndex);
  573. str.push_back(0);
  574. mpz_set_str(mData->mInteger, &str[0], 0);
  575. *endptr = const_cast<char*>(value + endIndex);
  576. }
  577. GmpInt GmpInt::parseString(const char* str, char** endptr)
  578. {
  579. GmpInt retval(kNoInitialization);
  580. retval.parseValue(str, endptr);
  581. return retval;
  582. }
  583. //===========================================================================
  584. // Operator functions
  585. //===========================================================================
  586. GmpInt operator+(long lhs, const GmpInt& rhs)
  587. {
  588. GmpInt retval(GmpInt::kNoInitialization);
  589. if(lhs >= 0)
  590. mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, lhs);
  591. else
  592. mpz_sub_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs);
  593. return retval;
  594. }
  595. GmpInt operator-(long lhs, const GmpInt& rhs)
  596. {
  597. GmpInt retval(GmpInt::kNoInitialization);
  598. if(lhs >= 0)
  599. mpz_ui_sub(retval.mData->mInteger, lhs, rhs.mData->mInteger);
  600. else
  601. {
  602. mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs);
  603. mpz_neg(retval.mData->mInteger, retval.mData->mInteger);
  604. }
  605. return retval;
  606. }
  607. GmpInt operator*(long lhs, const GmpInt& rhs)
  608. {
  609. return rhs * lhs;
  610. }
  611. GmpInt operator/(long lhs, const GmpInt& rhs)
  612. {
  613. return GmpInt(lhs) / rhs;
  614. }
  615. GmpInt operator%(long lhs, const GmpInt& rhs)
  616. {
  617. return GmpInt(lhs) % rhs;
  618. }