decimal.hh 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  1. /*
  2. * Copyright (c) 2020 Stefan Krah. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. #ifndef LIBMPDECXX_DECIMAL_HH_
  28. #define LIBMPDECXX_DECIMAL_HH_
  29. #include <cassert>
  30. #include <cstddef>
  31. #include <cstdint>
  32. #include <algorithm>
  33. #include <atomic>
  34. #include <iostream>
  35. #include <limits>
  36. #include <memory>
  37. #include <stdexcept>
  38. #include <string>
  39. #include <type_traits>
  40. #include <utility>
  41. #include "mpdecimal.h"
  42. #undef iscanonical /* math.h */
  43. #undef isfinite /* math.h */
  44. #undef isinf /* math.h */
  45. #undef isnan /* math.h */
  46. #undef isnormal /* math.h */
  47. #undef issubnormal /* math.h */
  48. #undef iszero /* math.h */
  49. #undef isspecial /* ctype.h */
  50. #undef IMPORTEXPORT
  51. #ifdef _MSC_VER
  52. #if defined (BUILD_LIBMPDECXX)
  53. #define IMPORTEXPORT __declspec(dllexport)
  54. #elif defined(_DLL)
  55. #define IMPORTEXPORT __declspec(dllimport)
  56. #else
  57. #define IMPORTEXPORT
  58. #endif
  59. #define ALWAYS_INLINE __forceinline
  60. #else
  61. #define IMPORTEXPORT
  62. #define ALWAYS_INLINE inline __attribute__ ((always_inline))
  63. #endif
  64. namespace decimal {
  65. /******************************************************************************/
  66. /* Constants from libmpdec */
  67. /******************************************************************************/
  68. enum round {
  69. ROUND_UP = MPD_ROUND_UP, /* round away from 0 */
  70. ROUND_DOWN = MPD_ROUND_DOWN, /* round toward 0 (truncate) */
  71. ROUND_CEILING = MPD_ROUND_CEILING, /* round toward +infinity */
  72. ROUND_FLOOR = MPD_ROUND_FLOOR, /* round toward -infinity */
  73. ROUND_HALF_UP = MPD_ROUND_HALF_UP, /* 0.5 is rounded up */
  74. ROUND_HALF_DOWN = MPD_ROUND_HALF_DOWN, /* 0.5 is rounded down */
  75. ROUND_HALF_EVEN = MPD_ROUND_HALF_EVEN, /* 0.5 is rounded to even */
  76. ROUND_05UP = MPD_ROUND_05UP, /* round zero or five away from 0 */
  77. ROUND_TRUNC = MPD_ROUND_TRUNC, /* truncate, but set infinity */
  78. ROUND_GUARD = MPD_ROUND_GUARD
  79. };
  80. /*
  81. * Aliases for a spelling that is consistent with the exceptions below.
  82. * Use whichever form you prefer.
  83. */
  84. constexpr uint32_t DecClamped = MPD_Clamped;
  85. constexpr uint32_t DecConversionSyntax = MPD_Conversion_syntax;
  86. constexpr uint32_t DecDivisionByZero = MPD_Division_by_zero;
  87. constexpr uint32_t DecDivisionImpossible = MPD_Division_impossible;
  88. constexpr uint32_t DecDivisionUndefined = MPD_Division_undefined;
  89. constexpr uint32_t DecFpuError = MPD_Fpu_error; /* unused */
  90. constexpr uint32_t DecInexact = MPD_Inexact;
  91. constexpr uint32_t DecInvalidContext = MPD_Invalid_context;
  92. constexpr uint32_t DecInvalidOperation = MPD_Invalid_operation;
  93. constexpr uint32_t DecMallocError = MPD_Malloc_error;
  94. constexpr uint32_t DecNotImplemented = MPD_Not_implemented; /* unused */
  95. constexpr uint32_t DecOverflow = MPD_Overflow;
  96. constexpr uint32_t DecRounded = MPD_Rounded;
  97. constexpr uint32_t DecSubnormal = MPD_Subnormal;
  98. constexpr uint32_t DecUnderflow = MPD_Underflow;
  99. /* Flag sets */
  100. constexpr uint32_t DecIEEEInvalidOperation = MPD_IEEE_Invalid_operation;
  101. /* DecConversionSyntax */
  102. /* DecDivisionImpossible */
  103. /* DecDivisionUndefined */
  104. /* DecFpuError */
  105. /* DecInvalidContext */
  106. /* DecInvalidOperation */
  107. /* DecMallocError */
  108. constexpr uint32_t DecErrors = MPD_Errors;
  109. /* DecIEEEInvalidOperation */
  110. /* DecDivisionByZero */
  111. constexpr uint32_t DecMaxStatus = MPD_Max_status;
  112. /* All flags */
  113. /* IEEEContext(): common arguments */
  114. constexpr int DECIMAL32 = MPD_DECIMAL32;
  115. constexpr int DECIMAL64 = MPD_DECIMAL64;
  116. constexpr int DECIMAL128 = MPD_DECIMAL128;
  117. /* IEEEContext(): maximum argument value */
  118. constexpr int IEEE_CONTEXT_MAX_BITS = MPD_IEEE_CONTEXT_MAX_BITS;
  119. /******************************************************************************/
  120. /* Decimal Exceptions */
  121. /******************************************************************************/
  122. class DecimalException : public std::runtime_error {
  123. using std::runtime_error::runtime_error;
  124. };
  125. /* Signals */
  126. class IEEEInvalidOperation : public DecimalException {
  127. using DecimalException::DecimalException;
  128. };
  129. class DivisionByZero : public DecimalException {
  130. using DecimalException::DecimalException;
  131. };
  132. class Overflow : public DecimalException {
  133. using DecimalException::DecimalException;
  134. };
  135. class Underflow : public DecimalException {
  136. using DecimalException::DecimalException;
  137. };
  138. class Subnormal : public DecimalException {
  139. using DecimalException::DecimalException;
  140. };
  141. class Inexact : public DecimalException {
  142. using DecimalException::DecimalException;
  143. };
  144. class Rounded : public DecimalException {
  145. using DecimalException::DecimalException;
  146. };
  147. class Clamped : public DecimalException {
  148. using DecimalException::DecimalException;
  149. };
  150. /* Conditions */
  151. class InvalidOperation : public IEEEInvalidOperation {
  152. using IEEEInvalidOperation::IEEEInvalidOperation;
  153. };
  154. class ConversionSyntax : public IEEEInvalidOperation {
  155. using IEEEInvalidOperation::IEEEInvalidOperation;
  156. };
  157. class DivisionImpossible : public IEEEInvalidOperation {
  158. using IEEEInvalidOperation::IEEEInvalidOperation;
  159. };
  160. class DivisionUndefined : public IEEEInvalidOperation {
  161. using IEEEInvalidOperation::IEEEInvalidOperation;
  162. };
  163. /******************************************************************************/
  164. /* Other Exceptions */
  165. /******************************************************************************/
  166. class MallocError : public DecimalException {
  167. using DecimalException::DecimalException;
  168. };
  169. class RuntimeError : public DecimalException {
  170. using DecimalException::DecimalException;
  171. };
  172. class ValueError : public DecimalException {
  173. using DecimalException::DecimalException;
  174. };
  175. /******************************************************************************/
  176. /* Context object */
  177. /******************************************************************************/
  178. class Context;
  179. IMPORTEXPORT extern Context context_template;
  180. #if defined(__OpenBSD__) || defined(__sun) || defined(_MSC_VER) && defined(_DLL)
  181. IMPORTEXPORT Context& getcontext();
  182. static thread_local Context& context{getcontext()};
  183. #else
  184. extern thread_local Context context;
  185. #endif
  186. class Context {
  187. private:
  188. mpd_context_t ctx;
  189. IMPORTEXPORT static void raiseit(uint32_t status);
  190. public:
  191. /***********************************************************************/
  192. /* Constructors */
  193. /***********************************************************************/
  194. Context(const Context& c) = default;
  195. Context(Context&& c) = default;
  196. explicit Context(const mpd_context_t &m) noexcept : ctx(m) {}
  197. explicit Context(mpd_ssize_t prec=context_template.prec(),
  198. mpd_ssize_t emax=context_template.emax(),
  199. mpd_ssize_t emin=context_template.emin(),
  200. int round=context_template.round(),
  201. uint32_t traps=context_template.traps(),
  202. int clamp=context_template.clamp(),
  203. int allcr=context_template.allcr()) {
  204. this->prec(prec);
  205. this->emax(emax);
  206. this->emin(emin);
  207. this->traps(traps);
  208. this->round(round);
  209. this->clamp(clamp);
  210. this->allcr(allcr);
  211. this->ctx.status = 0;
  212. this->ctx.newtrap = 0;
  213. }
  214. /***********************************************************************/
  215. /* Destructor */
  216. /***********************************************************************/
  217. ~Context() noexcept = default;
  218. /***********************************************************************/
  219. /* Assignment operators */
  220. /***********************************************************************/
  221. Context& operator= (const Context& c) = default;
  222. Context& operator= (Context&& c) = default;
  223. /***********************************************************************/
  224. /* Comparison operators */
  225. /***********************************************************************/
  226. bool operator== (const Context& other) const noexcept {
  227. return ctx.prec == other.ctx.prec &&
  228. ctx.emax == other.ctx.emax &&
  229. ctx.emin == other.ctx.emin &&
  230. ctx.traps == other.ctx.traps &&
  231. ctx.status == other.ctx.status &&
  232. ctx.round == other.ctx.round &&
  233. ctx.clamp == other.ctx.clamp &&
  234. ctx.allcr == other.ctx.allcr &&
  235. ctx.newtrap == other.ctx.newtrap;
  236. }
  237. bool operator!= (const Context& other) const noexcept {
  238. return !(*this == other);
  239. }
  240. /***********************************************************************/
  241. /* Accessors */
  242. /***********************************************************************/
  243. /* Get pointers to the full context */
  244. ALWAYS_INLINE mpd_context_t *get() { return &ctx; }
  245. ALWAYS_INLINE const mpd_context_t *getconst() const { return &ctx; }
  246. /* Get individual fields */
  247. ALWAYS_INLINE mpd_ssize_t prec() const { return ctx.prec; }
  248. ALWAYS_INLINE mpd_ssize_t emax() const { return ctx.emax; }
  249. ALWAYS_INLINE mpd_ssize_t emin() const { return ctx.emin; }
  250. ALWAYS_INLINE int round() const { return ctx.round; }
  251. ALWAYS_INLINE uint32_t status() const { return ctx.status; }
  252. ALWAYS_INLINE uint32_t traps() const { return ctx.traps; }
  253. ALWAYS_INLINE int clamp() const { return ctx.clamp; }
  254. ALWAYS_INLINE int allcr() const { return ctx.allcr; }
  255. ALWAYS_INLINE int64_t etiny() const { return mpd_etiny(&ctx); }
  256. ALWAYS_INLINE int64_t etop() const { return mpd_etop(&ctx); }
  257. /* Set individual fields */
  258. ALWAYS_INLINE void prec(mpd_ssize_t v) {
  259. if (!mpd_qsetprec(&ctx, v)) {
  260. throw ValueError("valid range for prec is [1, MAX_PREC]");
  261. }
  262. }
  263. ALWAYS_INLINE void emax(mpd_ssize_t v) {
  264. if (!mpd_qsetemax(&ctx, v)) {
  265. throw ValueError("valid range for emax is [0, MAX_EMAX]");
  266. }
  267. }
  268. ALWAYS_INLINE void emin(mpd_ssize_t v) {
  269. if (!mpd_qsetemin(&ctx, v)) {
  270. throw ValueError("valid range for emin is [MIN_EMIN, 0]");
  271. }
  272. }
  273. ALWAYS_INLINE void round(int v) {
  274. if (!mpd_qsetround(&ctx, v)) {
  275. throw ValueError("valid values for rounding are:\n"
  276. " [ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN,\n"
  277. " ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN,\n"
  278. " ROUND_05UP]");
  279. }
  280. }
  281. ALWAYS_INLINE void status(uint32_t v) {
  282. if (!mpd_qsetstatus(&ctx, v)) {
  283. throw ValueError("invalid status flag");
  284. }
  285. }
  286. ALWAYS_INLINE void traps(uint32_t v) {
  287. if (!mpd_qsettraps(&ctx, v)) {
  288. throw ValueError("invalid status flag");
  289. }
  290. }
  291. ALWAYS_INLINE void clamp(int v) {
  292. if (!mpd_qsetclamp(&ctx, v)) {
  293. throw ValueError("invalid value for clamp");
  294. }
  295. }
  296. ALWAYS_INLINE void allcr(int v) {
  297. if (!mpd_qsetcr(&ctx, v)) {
  298. throw ValueError("invalid value for allcr");
  299. }
  300. }
  301. /***********************************************************************/
  302. /* Status and exception handling */
  303. /***********************************************************************/
  304. /* Add flags to status and raise an exception if a relevant trap is active */
  305. ALWAYS_INLINE void raise(uint32_t flags) {
  306. ctx.status |= (flags & ~MPD_Malloc_error);
  307. const uint32_t active_traps = flags & (ctx.traps|MPD_Malloc_error);
  308. if (active_traps) {
  309. raiseit(active_traps);
  310. }
  311. }
  312. /* Add selected status flags */
  313. ALWAYS_INLINE void add_status(uint32_t flags) {
  314. if (flags > MPD_Max_status) {
  315. throw ValueError("invalid flags");
  316. }
  317. ctx.status |= flags;
  318. }
  319. /* Clear all status flags */
  320. ALWAYS_INLINE void clear_status() {
  321. ctx.status = 0;
  322. }
  323. /* Clear selected status flags */
  324. ALWAYS_INLINE void clear_status(uint32_t flags) {
  325. if (flags > MPD_Max_status) {
  326. throw ValueError("invalid flags");
  327. }
  328. ctx.status &= ~flags;
  329. }
  330. /* Add selected traps */
  331. ALWAYS_INLINE void add_traps(uint32_t flags) {
  332. if (flags > MPD_Max_status) {
  333. throw ValueError("invalid flags");
  334. }
  335. ctx.traps |= flags;
  336. }
  337. /* Clear all traps */
  338. ALWAYS_INLINE void clear_traps() {
  339. ctx.traps = 0;
  340. }
  341. /* Clear selected traps */
  342. ALWAYS_INLINE void clear_traps(uint32_t flags) {
  343. if (flags > MPD_Max_status) {
  344. throw ValueError("invalid flags");
  345. }
  346. ctx.traps &= ~flags;
  347. }
  348. /***********************************************************************/
  349. /* String conversion */
  350. /***********************************************************************/
  351. IMPORTEXPORT std::string repr() const;
  352. IMPORTEXPORT friend std::ostream& operator<<(std::ostream& os, const Context& c);
  353. };
  354. IMPORTEXPORT Context MaxContext();
  355. IMPORTEXPORT Context IEEEContext(int bits);
  356. /******************************************************************************/
  357. /* Util */
  358. /******************************************************************************/
  359. namespace util {
  360. template <typename dest_t, typename src_t>
  361. inline dest_t
  362. safe_downcast(src_t v) {
  363. if (v < std::numeric_limits<dest_t>::min() ||
  364. v > std::numeric_limits<dest_t>::max()) {
  365. throw ValueError("cast changes the original value");
  366. }
  367. return static_cast<dest_t>(v);
  368. }
  369. inline std::shared_ptr<const char>
  370. shared_cp(const char *cp) {
  371. if (cp == nullptr) {
  372. throw RuntimeError("util::shared_cp: invalid nullptr argument");
  373. }
  374. return std::shared_ptr<const char>(cp, [](const char *s){ mpd_free(const_cast<char *>(s)); });
  375. }
  376. inline std::string
  377. string_from_cp(const char *cp) {
  378. const auto p = shared_cp(cp);
  379. return std::string(p.get());
  380. }
  381. template <typename T>
  382. struct int64_compat {
  383. #define INT64_SUBSET(T) \
  384. (INT64_MIN <= std::numeric_limits<T>::min() && std::numeric_limits<T>::max() <= INT64_MAX)
  385. static const bool value = std::is_same<T, int8_t>::value ||
  386. std::is_same<T, int16_t>::value ||
  387. std::is_same<T, int32_t>::value ||
  388. std::is_same<T, int64_t>::value ||
  389. (std::is_same<T, signed char>::value && INT64_SUBSET(signed char)) ||
  390. (std::is_same<T, short>::value && INT64_SUBSET(short)) ||
  391. (std::is_same<T, int>::value && INT64_SUBSET(int)) ||
  392. (std::is_same<T, long>::value && INT64_SUBSET(long)) ||
  393. (std::is_same<T, long long>::value && INT64_SUBSET(long long));
  394. };
  395. template <typename T>
  396. struct uint64_compat {
  397. #define UINT64_SUBSET(T) (std::numeric_limits<T>::max() <= UINT64_MAX)
  398. static const bool value = std::is_same<T, uint8_t>::value ||
  399. std::is_same<T, uint16_t>::value ||
  400. std::is_same<T, uint32_t>::value ||
  401. std::is_same<T, uint64_t>::value ||
  402. (std::is_same<T, unsigned char>::value && UINT64_SUBSET(unsigned char)) ||
  403. (std::is_same<T, unsigned short>::value && UINT64_SUBSET(unsigned short)) ||
  404. (std::is_same<T, unsigned int>::value && UINT64_SUBSET(unsigned int)) ||
  405. (std::is_same<T, unsigned long>::value && UINT64_SUBSET(unsigned long)) ||
  406. (std::is_same<T, unsigned long long>::value && UINT64_SUBSET(unsigned long long));
  407. };
  408. #define ENABLE_IF_SIGNED(T) \
  409. template<typename T, \
  410. typename = typename std::enable_if<util::int64_compat<T>::value>::type>
  411. #define ENABLE_IF_UNSIGNED(T) \
  412. template<typename T, \
  413. typename = typename std::enable_if<util::uint64_compat<T>::value>::type, typename = void>
  414. #define ENABLE_IF_INTEGRAL(T) \
  415. template<typename T, \
  416. typename = typename std::enable_if<util::int64_compat<T>::value || util::uint64_compat<T>::value>::type>
  417. #define ASSERT_SIGNED(T) \
  418. static_assert(util::int64_compat<T>::value, \
  419. "internal error: selected type is not int64 compatible")
  420. #define ASSERT_UNSIGNED(T) \
  421. static_assert(util::uint64_compat<T>::value, \
  422. "internal error: selected type is not uint64 compatible")
  423. #define ASSERT_INTEGRAL(T) \
  424. static_assert(util::int64_compat<T>::value || util::uint64_compat<T>::value, \
  425. "internal error: selected type is not a suitable integer type")
  426. } // namespace util
  427. /******************************************************************************/
  428. /* Decimal object */
  429. /******************************************************************************/
  430. constexpr mpd_ssize_t MINALLOC = 4;
  431. class Decimal {
  432. private:
  433. mpd_uint_t data[MINALLOC] = {0};
  434. mpd_t value {
  435. MPD_STATIC|MPD_STATIC_DATA|MPD_SNAN, /* flags */
  436. 0, /* exp */
  437. 0, /* digits */
  438. 0, /* len */
  439. MINALLOC, /* alloc */
  440. data /* data */
  441. };
  442. /* mpd_t accessors */
  443. ALWAYS_INLINE bool isstatic() const { return value.data == data; }
  444. /* reset rhs to snan after moving data to lhs */
  445. ALWAYS_INLINE void reset() {
  446. value = {
  447. MPD_STATIC|MPD_STATIC_DATA|MPD_SNAN, /* flags */
  448. 0, /* exp */
  449. 0, /* digits */
  450. 0, /* len */
  451. MINALLOC, /* alloc */
  452. data /* data */
  453. };
  454. }
  455. /* Copy flags, preserving memory attributes of result. */
  456. ALWAYS_INLINE uint8_t
  457. copy_flags(const uint8_t rflags, const uint8_t aflags) {
  458. return (rflags & (MPD_STATIC|MPD_DATAFLAGS)) |
  459. (aflags & ~(MPD_STATIC|MPD_DATAFLAGS));
  460. }
  461. ALWAYS_INLINE void
  462. copy_value(const mpd_t *const src, const bool fastcopy) {
  463. assert(mpd_isstatic(&value));
  464. assert(mpd_isstatic(src));
  465. assert(value.alloc >= MINALLOC);
  466. assert(src->alloc >= MINALLOC);
  467. assert(MPD_MINALLOC == MINALLOC);
  468. if (fastcopy) {
  469. value.data[0] = src->data[0];
  470. value.data[1] = src->data[1];
  471. value.data[2] = src->data[2];
  472. value.data[3] = src->data[3];
  473. value.flags = copy_flags(value.flags, src->flags);
  474. value.exp = src->exp;
  475. value.digits = src->digits;
  476. value.len = src->len;
  477. } else {
  478. if (!mpd_qcopy_cxx(&value, src)) {
  479. context.raise(MPD_Malloc_error);
  480. }
  481. }
  482. }
  483. ALWAYS_INLINE void
  484. move_value(const mpd_t *const src, const bool fastcopy) {
  485. assert(mpd_isstatic(&value));
  486. assert(mpd_isstatic(src));
  487. assert(value.alloc >= MINALLOC);
  488. assert(src->alloc >= MINALLOC);
  489. assert(MPD_MINALLOC == MINALLOC);
  490. if (fastcopy) {
  491. value.data[0] = src->data[0];
  492. value.data[1] = src->data[1];
  493. value.data[2] = src->data[2];
  494. value.data[3] = src->data[3];
  495. value.flags = copy_flags(value.flags, src->flags);
  496. value.exp = src->exp;
  497. value.digits = src->digits;
  498. value.len = src->len;
  499. }
  500. else {
  501. assert(mpd_isdynamic_data(src));
  502. if (mpd_isdynamic_data(&value)) {
  503. mpd_free(value.data);
  504. }
  505. value = *src;
  506. assert(mpd_isstatic(&value));
  507. assert(mpd_isdynamic_data(&value));
  508. }
  509. }
  510. ALWAYS_INLINE Decimal unary_func_status(
  511. int (* func)(mpd_t *, const mpd_t *, uint32_t *)) const {
  512. Decimal result;
  513. uint32_t status = 0;
  514. if (!func(result.get(), getconst(), &status)) {
  515. throw MallocError("out of memory");
  516. }
  517. return result;
  518. }
  519. ALWAYS_INLINE Decimal unary_func(
  520. void (* func)(mpd_t *, const mpd_t *, const mpd_context_t *, uint32_t *),
  521. Context& c=context) const {
  522. Decimal result;
  523. uint32_t status = 0;
  524. func(result.get(), getconst(), c.getconst(), &status);
  525. c.raise(status);
  526. return result;
  527. }
  528. ALWAYS_INLINE Decimal binary_func_noctx(
  529. int (* func)(mpd_t *, const mpd_t *, const mpd_t *),
  530. const Decimal& other) const {
  531. Decimal result;
  532. (void)func(result.get(), getconst(), other.getconst());
  533. return result;
  534. }
  535. ALWAYS_INLINE Decimal int_binary_func(
  536. int (* func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_context_t *, uint32_t *),
  537. const Decimal& other,
  538. Context& c=context) const {
  539. Decimal result;
  540. uint32_t status = 0;
  541. (void)func(result.get(), getconst(), other.getconst(), c.getconst(), &status);
  542. c.raise(status);
  543. return result;
  544. }
  545. ALWAYS_INLINE Decimal binary_func(
  546. void (* func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_context_t *, uint32_t *),
  547. const Decimal& other,
  548. Context& c=context) const {
  549. Decimal result;
  550. uint32_t status = 0;
  551. func(result.get(), getconst(), other.getconst(), c.getconst(), &status);
  552. c.raise(status);
  553. return result;
  554. }
  555. ALWAYS_INLINE Decimal& inplace_binary_func(
  556. void (* func)(mpd_t *, const mpd_t *, const mpd_t *, const mpd_context_t *, uint32_t *),
  557. const Decimal& other,
  558. Context& c=context) {
  559. uint32_t status = 0;
  560. func(get(), getconst(), other.getconst(), c.getconst(), &status);
  561. c.raise(status);
  562. return *this;
  563. }
  564. ALWAYS_INLINE Decimal inplace_shiftl(const int64_t n, Context& c=context) {
  565. uint32_t status = 0;
  566. mpd_ssize_t nn = util::safe_downcast<mpd_ssize_t, int64_t>(n);
  567. mpd_qshiftl(get(), getconst(), nn, &status);
  568. c.raise(status);
  569. return *this;
  570. }
  571. ALWAYS_INLINE Decimal inplace_shiftr(const int64_t n, Context& c=context) {
  572. uint32_t status = 0;
  573. mpd_ssize_t nn = util::safe_downcast<mpd_ssize_t, int64_t>(n);
  574. mpd_qshiftr(get(), getconst(), nn, &status);
  575. c.raise(status);
  576. return *this;
  577. }
  578. public:
  579. /***********************************************************************/
  580. /* Exact conversions regardless of context */
  581. /***********************************************************************/
  582. /* Implicit */
  583. Decimal() noexcept = default;
  584. Decimal(const Decimal& other) { *this = other; }
  585. Decimal(Decimal&& other) noexcept { *this = std::move(other); }
  586. ENABLE_IF_SIGNED(T)
  587. Decimal(const T& other) {
  588. ASSERT_SIGNED(T);
  589. uint32_t status = 0;
  590. mpd_qset_i64_exact(&value, other, &status);
  591. context.raise(status);
  592. }
  593. ENABLE_IF_UNSIGNED(T)
  594. Decimal(const T& other) {
  595. ASSERT_UNSIGNED(T);
  596. uint32_t status = 0;
  597. mpd_qset_u64_exact(&value, other, &status);
  598. context.raise(status);
  599. }
  600. /* Explicit */
  601. explicit Decimal(const char * const s) {
  602. uint32_t status = 0;
  603. if (s == nullptr) {
  604. throw ValueError("Decimal: string argument in constructor is NULL");
  605. }
  606. mpd_qset_string_exact(&value, s, &status);
  607. context.raise(status);
  608. }
  609. explicit Decimal(const std::string& s) {
  610. uint32_t status = 0;
  611. mpd_qset_string_exact(&value, s.c_str(), &status);
  612. context.raise(status);
  613. }
  614. explicit Decimal(const mpd_uint128_triple_t& triple) {
  615. uint32_t status = 0;
  616. if (mpd_from_uint128_triple(&value, &triple, &status) < 0) {
  617. context.raise(status);
  618. }
  619. }
  620. /***********************************************************************/
  621. /* Inexact conversions that use a context */
  622. /***********************************************************************/
  623. explicit Decimal(const Decimal& other, Context& c) {
  624. const mpd_context_t *ctx = c.getconst();
  625. *this = other;
  626. if (mpd_isnan(&value) && value.digits > ctx->prec - ctx->clamp) {
  627. /* Special case: too many NaN payload digits */
  628. mpd_setspecial(&value, MPD_POS, MPD_NAN);
  629. c.raise(MPD_Conversion_syntax);
  630. }
  631. else {
  632. uint32_t status = 0;
  633. mpd_qfinalize(&value, ctx, &status);
  634. c.raise(status);
  635. }
  636. }
  637. ENABLE_IF_SIGNED(T)
  638. explicit Decimal(const T& other, Context& c) {
  639. ASSERT_SIGNED(T);
  640. uint32_t status = 0;
  641. mpd_qset_i64(&value, other, c.getconst(), &status);
  642. c.raise(status);
  643. }
  644. ENABLE_IF_UNSIGNED(T)
  645. explicit Decimal(const T& other, Context& c) {
  646. ASSERT_UNSIGNED(T);
  647. uint32_t status = 0;
  648. mpd_qset_u64(&value, other, c.getconst(), &status);
  649. c.raise(status);
  650. }
  651. explicit Decimal(const char * const s, Context& c) {
  652. uint32_t status = 0;
  653. if (s == nullptr) {
  654. throw ValueError("Decimal: string argument in constructor is NULL");
  655. }
  656. mpd_qset_string(&value, s, c.getconst(), &status);
  657. c.raise(status);
  658. }
  659. explicit Decimal(const std::string& s, Context& c) {
  660. uint32_t status = 0;
  661. mpd_qset_string(&value, s.c_str(), c.getconst(), &status);
  662. c.raise(status);
  663. }
  664. /***********************************************************************/
  665. /* Accessors */
  666. /***********************************************************************/
  667. ALWAYS_INLINE mpd_t *get() { return &value; }
  668. ALWAYS_INLINE const mpd_t *getconst() const { return &value; }
  669. ALWAYS_INLINE int sign() const { return mpd_isnegative(&value) ? -1 : 1; }
  670. ALWAYS_INLINE Decimal coeff() const {
  671. if (isspecial()) {
  672. throw ValueError("coefficient is undefined for special values");
  673. }
  674. Decimal result = *this;
  675. mpd_set_positive(&result.value);
  676. result.value.exp = 0;
  677. return result;
  678. }
  679. ALWAYS_INLINE int64_t exponent() const {
  680. if (isspecial()) {
  681. throw ValueError("exponent is undefined for special values");
  682. }
  683. return value.exp;
  684. }
  685. ALWAYS_INLINE Decimal payload() const {
  686. if (!isnan()) {
  687. throw ValueError("payload is only defined for NaNs");
  688. }
  689. if (value.len == 0) {
  690. return Decimal(0);
  691. }
  692. Decimal result = *this;
  693. mpd_set_flags(&result.value, 0);
  694. result.value.exp = 0;
  695. return result;
  696. }
  697. /***********************************************************************/
  698. /* Destructor */
  699. /***********************************************************************/
  700. ~Decimal() { if (value.data != data) mpd_del(&value); }
  701. /***********************************************************************/
  702. /* Assignment operators */
  703. /***********************************************************************/
  704. ALWAYS_INLINE Decimal& operator= (const Decimal& other) {
  705. copy_value(other.getconst(), other.isstatic());
  706. return *this;
  707. }
  708. ALWAYS_INLINE Decimal& operator= (Decimal&& other) noexcept {
  709. if (this != &other) {
  710. move_value(other.getconst(), other.isstatic());
  711. other.reset();
  712. }
  713. return *this;
  714. }
  715. ALWAYS_INLINE Decimal& operator+= (const Decimal& other) { return inplace_binary_func(mpd_qadd, other); }
  716. ALWAYS_INLINE Decimal& operator-= (const Decimal& other) { return inplace_binary_func(mpd_qsub, other); }
  717. ALWAYS_INLINE Decimal& operator*= (const Decimal& other) { return inplace_binary_func(mpd_qmul, other); }
  718. ALWAYS_INLINE Decimal& operator/= (const Decimal& other) { return inplace_binary_func(mpd_qdiv, other); }
  719. ALWAYS_INLINE Decimal& operator%= (const Decimal& other) { return inplace_binary_func(mpd_qrem, other); }
  720. /***********************************************************************/
  721. /* Comparison operators */
  722. /***********************************************************************/
  723. ALWAYS_INLINE bool operator== (const Decimal& other) const {
  724. uint32_t status = 0;
  725. const int r = mpd_qcmp(getconst(), other.getconst(), &status);
  726. if (r == INT_MAX) {
  727. if (issnan() || other.issnan()) {
  728. context.raise(status);
  729. }
  730. return false;
  731. }
  732. return r == 0;
  733. }
  734. ALWAYS_INLINE bool operator!= (const Decimal& other) const {
  735. uint32_t status = 0;
  736. const int r = mpd_qcmp(getconst(), other.getconst(), &status);
  737. if (r == INT_MAX) {
  738. if (issnan() || other.issnan()) {
  739. context.raise(status);
  740. }
  741. return true;
  742. }
  743. return r != 0;
  744. }
  745. ALWAYS_INLINE bool operator< (const Decimal& other) const {
  746. uint32_t status = 0;
  747. const int r = mpd_qcmp(getconst(), other.getconst(), &status);
  748. if (r == INT_MAX) {
  749. context.raise(status);
  750. return false;
  751. }
  752. return r < 0;
  753. }
  754. ALWAYS_INLINE bool operator<= (const Decimal& other) const {
  755. uint32_t status = 0;
  756. const int r = mpd_qcmp(getconst(), other.getconst(), &status);
  757. if (r == INT_MAX) {
  758. context.raise(status);
  759. return false;
  760. }
  761. return r <= 0;
  762. }
  763. ALWAYS_INLINE bool operator>= (const Decimal& other) const {
  764. uint32_t status = 0;
  765. const int r = mpd_qcmp(getconst(), other.getconst(), &status);
  766. if (r == INT_MAX) {
  767. context.raise(status);
  768. return false;
  769. }
  770. return r >= 0;
  771. }
  772. ALWAYS_INLINE bool operator> (const Decimal& other) const {
  773. uint32_t status = 0;
  774. const int r = mpd_qcmp(getconst(), other.getconst(), &status);
  775. if (r == INT_MAX) {
  776. context.raise(status);
  777. return false;
  778. }
  779. return r > 0;
  780. }
  781. /***********************************************************************/
  782. /* Unary arithmetic operators */
  783. /***********************************************************************/
  784. ALWAYS_INLINE Decimal operator- () const { return unary_func(mpd_qminus); }
  785. ALWAYS_INLINE Decimal operator+ () const { return unary_func(mpd_qplus); }
  786. /***********************************************************************/
  787. /* Binary arithmetic operators */
  788. /***********************************************************************/
  789. ALWAYS_INLINE Decimal operator+ (const Decimal& other) const { return binary_func(mpd_qadd, other); }
  790. ALWAYS_INLINE Decimal operator- (const Decimal& other) const { return binary_func(mpd_qsub, other); }
  791. ALWAYS_INLINE Decimal operator* (const Decimal& other) const { return binary_func(mpd_qmul, other); }
  792. ALWAYS_INLINE Decimal operator/ (const Decimal& other) const { return binary_func(mpd_qdiv, other); }
  793. ALWAYS_INLINE Decimal operator% (const Decimal& other) const { return binary_func(mpd_qrem, other); }
  794. /***********************************************************************/
  795. /* Predicates */
  796. /***********************************************************************/
  797. /* Predicates, no context arg */
  798. ALWAYS_INLINE bool iscanonical() const { return mpd_iscanonical(getconst()); }
  799. ALWAYS_INLINE bool isfinite() const { return mpd_isfinite(getconst()); }
  800. ALWAYS_INLINE bool isinfinite() const { return mpd_isinfinite(getconst()); }
  801. ALWAYS_INLINE bool isspecial() const { return mpd_isspecial(getconst()); }
  802. ALWAYS_INLINE bool isnan() const { return mpd_isnan(getconst()); }
  803. ALWAYS_INLINE bool isqnan() const { return mpd_isqnan(getconst()); }
  804. ALWAYS_INLINE bool issnan() const { return mpd_issnan(getconst()); }
  805. ALWAYS_INLINE bool issigned() const { return mpd_issigned(getconst()); }
  806. ALWAYS_INLINE bool iszero() const { return mpd_iszero(getconst()); }
  807. ALWAYS_INLINE bool isinteger() const { return mpd_isinteger(getconst()); }
  808. /* Predicates, optional context arg */
  809. ALWAYS_INLINE bool isnormal(const Context& c=context) const { return mpd_isnormal(getconst(), c.getconst()); }
  810. ALWAYS_INLINE bool issubnormal(const Context& c=context) const { return mpd_issubnormal(getconst(), c.getconst()); }
  811. /***********************************************************************/
  812. /* Unary functions */
  813. /***********************************************************************/
  814. /* Unary functions, no context arg */
  815. ALWAYS_INLINE int64_t adjexp() const {
  816. if (isspecial()) {
  817. throw ValueError("adjusted exponent undefined for special values");
  818. }
  819. return mpd_adjexp(getconst());
  820. }
  821. ALWAYS_INLINE Decimal canonical() const { return *this; }
  822. ALWAYS_INLINE Decimal copy() const { return unary_func_status(mpd_qcopy); }
  823. ALWAYS_INLINE Decimal copy_abs() const { return unary_func_status(mpd_qcopy_abs); }
  824. ALWAYS_INLINE Decimal copy_negate() const { return unary_func_status(mpd_qcopy_negate); }
  825. /* Unary functions, optional context arg */
  826. ALWAYS_INLINE std::string number_class(Context& c=context) const { return mpd_class(getconst(), c.getconst()); }
  827. ALWAYS_INLINE Decimal abs(Context& c=context) const { return unary_func(mpd_qabs, c); }
  828. ALWAYS_INLINE Decimal ceil(Context& c=context) const { return unary_func(mpd_qceil, c); }
  829. ALWAYS_INLINE Decimal exp(Context& c=context) const { return unary_func(mpd_qexp, c); }
  830. ALWAYS_INLINE Decimal floor(Context& c=context) const { return unary_func(mpd_qfloor, c); }
  831. ALWAYS_INLINE Decimal invroot(Context& c=context) const { return unary_func(mpd_qinvroot, c); }
  832. ALWAYS_INLINE Decimal logical_invert(Context& c=context) const { return unary_func(mpd_qinvert, c); }
  833. ALWAYS_INLINE Decimal ln(Context& c=context) const { return unary_func(mpd_qln, c); }
  834. ALWAYS_INLINE Decimal log10(Context& c=context) const { return unary_func(mpd_qlog10, c); }
  835. ALWAYS_INLINE Decimal logb(Context& c=context) const { return unary_func(mpd_qlogb, c); }
  836. ALWAYS_INLINE Decimal minus(Context& c=context) const { return unary_func(mpd_qminus, c); }
  837. ALWAYS_INLINE Decimal next_minus(Context& c=context) const { return unary_func(mpd_qnext_minus, c); }
  838. ALWAYS_INLINE Decimal next_plus(Context& c=context) const { return unary_func(mpd_qnext_plus, c); }
  839. ALWAYS_INLINE Decimal plus(Context& c=context) const { return unary_func(mpd_qplus, c); }
  840. ALWAYS_INLINE Decimal reduce(Context& c=context) const { return unary_func(mpd_qreduce, c); }
  841. ALWAYS_INLINE Decimal to_integral(Context& c=context) const { return unary_func(mpd_qround_to_int, c); }
  842. ALWAYS_INLINE Decimal to_integral_exact(Context& c=context) const { return unary_func(mpd_qround_to_intx, c); }
  843. ALWAYS_INLINE Decimal sqrt(Context& c=context) const { return unary_func(mpd_qsqrt, c); }
  844. ALWAYS_INLINE Decimal trunc(Context& c=context) const { return unary_func(mpd_qtrunc, c); }
  845. /***********************************************************************/
  846. /* Binary functions */
  847. /***********************************************************************/
  848. /* Binary functions, no context arg */
  849. ALWAYS_INLINE Decimal compare_total(const Decimal& other) const { return binary_func_noctx(mpd_compare_total, other); }
  850. ALWAYS_INLINE Decimal compare_total_mag(const Decimal& other) const { return binary_func_noctx(mpd_compare_total_mag, other); }
  851. /* Binary arithmetic functions, optional context arg */
  852. ALWAYS_INLINE Decimal add(const Decimal& other, Context& c=context) const { return binary_func(mpd_qadd, other, c); }
  853. ALWAYS_INLINE Decimal div(const Decimal& other, Context& c=context) const { return binary_func(mpd_qdiv, other, c); }
  854. ALWAYS_INLINE Decimal divint(const Decimal& other, Context& c=context) const { return binary_func(mpd_qdivint, other, c); }
  855. ALWAYS_INLINE Decimal compare(const Decimal& other, Context& c=context) const { return int_binary_func(mpd_qcompare, other, c); }
  856. ALWAYS_INLINE Decimal compare_signal(const Decimal& other, Context& c=context) const { return int_binary_func(mpd_qcompare_signal, other, c); }
  857. ALWAYS_INLINE Decimal logical_and(const Decimal& other, Context& c=context) const { return binary_func(mpd_qand, other, c); }
  858. ALWAYS_INLINE Decimal logical_or(const Decimal& other, Context& c=context) const { return binary_func(mpd_qor, other, c); }
  859. ALWAYS_INLINE Decimal logical_xor(const Decimal& other, Context& c=context) const { return binary_func(mpd_qxor, other, c); }
  860. ALWAYS_INLINE Decimal max(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmax, other, c); }
  861. ALWAYS_INLINE Decimal max_mag(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmax_mag, other, c); }
  862. ALWAYS_INLINE Decimal min(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmin, other, c); }
  863. ALWAYS_INLINE Decimal min_mag(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmin_mag, other, c); }
  864. ALWAYS_INLINE Decimal mul(const Decimal& other, Context& c=context) const { return binary_func(mpd_qmul, other, c); }
  865. ALWAYS_INLINE Decimal next_toward(const Decimal& other, Context& c=context) const { return binary_func(mpd_qnext_toward, other, c); }
  866. ALWAYS_INLINE Decimal pow(const Decimal& other, Context& c=context) const { return binary_func(mpd_qpow, other, c); }
  867. ALWAYS_INLINE Decimal quantize(const Decimal& other, Context& c=context) const { return binary_func(mpd_qquantize, other, c); }
  868. ALWAYS_INLINE Decimal rem(const Decimal& other, Context& c=context) const { return binary_func(mpd_qrem, other, c); }
  869. ALWAYS_INLINE Decimal rem_near(const Decimal& other, Context& c=context) const { return binary_func(mpd_qrem_near, other, c); }
  870. ALWAYS_INLINE Decimal rotate(const Decimal& other, Context& c=context) const { return binary_func(mpd_qrotate, other, c); }
  871. ALWAYS_INLINE Decimal scaleb(const Decimal& other, Context& c=context) const { return binary_func(mpd_qscaleb, other, c); }
  872. ALWAYS_INLINE Decimal shift(const Decimal& other, Context& c=context) const { return binary_func(mpd_qshift, other, c); }
  873. ALWAYS_INLINE Decimal sub(const Decimal& other, Context& c=context) const { return binary_func(mpd_qsub, other, c); }
  874. /* Binary arithmetic function, two return values */
  875. ALWAYS_INLINE std::pair<Decimal, Decimal> divmod(const Decimal& other, Context& c=context) const {
  876. std::pair<Decimal, Decimal> result;
  877. uint32_t status = 0;
  878. mpd_qdivmod(result.first.get(), result.second.get(), getconst(), other.getconst(), c.getconst(), &status);
  879. c.raise(status);
  880. return result;
  881. }
  882. /***********************************************************************/
  883. /* Ternary functions */
  884. /***********************************************************************/
  885. ALWAYS_INLINE Decimal fma(const Decimal& other, const Decimal& third, Context& c=context) const {
  886. Decimal result;
  887. uint32_t status = 0;
  888. mpd_qfma(result.get(), getconst(), other.getconst(), third.getconst(), c.getconst(), &status);
  889. c.raise(status);
  890. return result;
  891. }
  892. ALWAYS_INLINE Decimal powmod(const Decimal& other, const Decimal& third, Context& c=context) const {
  893. Decimal result;
  894. uint32_t status = 0;
  895. mpd_qpowmod(result.get(), getconst(), other.getconst(), third.getconst(), c.getconst(), &status);
  896. c.raise(status);
  897. return result;
  898. }
  899. /***********************************************************************/
  900. /* Irregular functions */
  901. /***********************************************************************/
  902. ALWAYS_INLINE Decimal apply(Context& c=context) const {
  903. Decimal result = *this;
  904. uint32_t status = 0;
  905. mpd_qfinalize(result.get(), c.getconst(), &status);
  906. c.raise(status);
  907. return result;
  908. }
  909. ALWAYS_INLINE int cmp(const Decimal& other) const {
  910. uint32_t status = 0;
  911. return mpd_qcmp(getconst(), other.getconst(), &status);
  912. }
  913. ALWAYS_INLINE int cmp_total(const Decimal& other) const {
  914. return mpd_cmp_total(getconst(), other.getconst());
  915. }
  916. ALWAYS_INLINE int cmp_total_mag(const Decimal& other) const {
  917. return mpd_cmp_total_mag(getconst(), other.getconst());
  918. }
  919. ALWAYS_INLINE Decimal copy_sign(const Decimal& other) const {
  920. Decimal result;
  921. uint32_t status = 0;
  922. if (!mpd_qcopy_sign(result.get(), getconst(), other.getconst(), &status)) {
  923. throw MallocError("out of memory");
  924. }
  925. return result;
  926. }
  927. ALWAYS_INLINE Decimal rescale(const int64_t exp, Context& c=context) const {
  928. Decimal result;
  929. uint32_t status = 0;
  930. mpd_ssize_t xexp = util::safe_downcast<mpd_ssize_t, int64_t>(exp);
  931. mpd_qrescale(result.get(), getconst(), xexp, c.getconst(), &status);
  932. c.raise(status);
  933. return result;
  934. }
  935. ALWAYS_INLINE bool same_quantum(const Decimal& other) const {
  936. return mpd_same_quantum(getconst(), other.getconst());
  937. }
  938. ALWAYS_INLINE Decimal shiftn(const int64_t n, Context& c=context) const {
  939. Decimal result;
  940. uint32_t status = 0;
  941. mpd_ssize_t nn = util::safe_downcast<mpd_ssize_t, int64_t>(n);
  942. mpd_qshiftn(result.get(), getconst(), nn, c.getconst(), &status);
  943. c.raise(status);
  944. return result;
  945. }
  946. ALWAYS_INLINE Decimal shiftl(const int64_t n, Context& c=context) const {
  947. Decimal result;
  948. uint32_t status = 0;
  949. mpd_ssize_t nn = util::safe_downcast<mpd_ssize_t, int64_t>(n);
  950. mpd_qshiftl(result.get(), getconst(), nn, &status);
  951. c.raise(status);
  952. return result;
  953. }
  954. ALWAYS_INLINE Decimal shiftr(const int64_t n, Context& c=context) const {
  955. Decimal result;
  956. uint32_t status = 0;
  957. mpd_ssize_t nn = util::safe_downcast<mpd_ssize_t, int64_t>(n);
  958. mpd_qshiftr(result.get(), getconst(), nn, &status);
  959. c.raise(status);
  960. return result;
  961. }
  962. IMPORTEXPORT static Decimal exact(const char *s, Context& c);
  963. IMPORTEXPORT static Decimal exact(const std::string& s, Context& c);
  964. IMPORTEXPORT static Decimal ln10(int64_t n, Context& c=context);
  965. IMPORTEXPORT static int32_t radix();
  966. /***********************************************************************/
  967. /* Integer conversion */
  968. /***********************************************************************/
  969. ALWAYS_INLINE int64_t i64() const {
  970. uint32_t status = 0;
  971. const int64_t result = mpd_qget_i64(getconst(), &status);
  972. if (status) {
  973. throw ValueError("cannot convert to int64_t");
  974. }
  975. return result;
  976. }
  977. ALWAYS_INLINE int32_t i32() const {
  978. uint32_t status = 0;
  979. const int32_t result = mpd_qget_i32(getconst(), &status);
  980. if (status) {
  981. throw ValueError("cannot convert to int32_t");
  982. }
  983. return result;
  984. }
  985. ALWAYS_INLINE uint64_t u64() const {
  986. uint32_t status = 0;
  987. const uint64_t result = mpd_qget_u64(getconst(), &status);
  988. if (status) {
  989. throw ValueError("cannot convert to uint64_t");
  990. }
  991. return result;
  992. }
  993. ALWAYS_INLINE uint32_t u32() const {
  994. uint32_t status = 0;
  995. const uint32_t result = mpd_qget_u32(getconst(), &status);
  996. if (status) {
  997. throw ValueError("cannot convert to uint32_t");
  998. }
  999. return result;
  1000. }
  1001. /***********************************************************************/
  1002. /* Triple conversion */
  1003. /***********************************************************************/
  1004. ALWAYS_INLINE mpd_uint128_triple_t as_uint128_triple() const {
  1005. return mpd_as_uint128_triple(getconst());
  1006. }
  1007. /***********************************************************************/
  1008. /* String conversion */
  1009. /***********************************************************************/
  1010. /* String representations */
  1011. IMPORTEXPORT std::string repr(bool capitals=true) const;
  1012. inline std::string to_sci(bool capitals=true) const {
  1013. const char *cp = mpd_to_sci(getconst(), capitals);
  1014. if (cp == nullptr) {
  1015. throw MallocError("out of memory");
  1016. }
  1017. return util::string_from_cp(cp);
  1018. }
  1019. inline std::string to_eng(bool capitals=true) const {
  1020. const char *cp = mpd_to_eng(getconst(), capitals);
  1021. if (cp == nullptr) {
  1022. throw MallocError("out of memory");
  1023. }
  1024. return util::string_from_cp(cp);
  1025. }
  1026. inline std::string format(const char *fmt, const Context& c=context) const {
  1027. uint32_t status = 0;
  1028. mpd_context_t ctx;
  1029. if (fmt == nullptr) {
  1030. throw ValueError("Decimal.format: fmt argument is NULL");
  1031. }
  1032. mpd_maxcontext(&ctx);
  1033. ctx.round = c.getconst()->round;
  1034. ctx.traps = 0;
  1035. const char *cp = mpd_qformat(getconst(), fmt, &ctx, &status);
  1036. if (cp == nullptr) {
  1037. if (status & MPD_Malloc_error) {
  1038. throw MallocError("out of memory");
  1039. }
  1040. else if (status & MPD_Invalid_operation) {
  1041. throw ValueError("invalid format string");
  1042. }
  1043. else {
  1044. throw RuntimeError("internal error: unexpected status");
  1045. }
  1046. }
  1047. return util::string_from_cp(cp);
  1048. }
  1049. inline std::string format(const std::string& s, const Context& c=context) const {
  1050. return format(s.c_str(), c);
  1051. }
  1052. IMPORTEXPORT friend std::ostream& operator<< (std::ostream& os, const Decimal& dec);
  1053. };
  1054. /***********************************************************************/
  1055. /* Reverse comparison operators */
  1056. /***********************************************************************/
  1057. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator==(const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) == self; }
  1058. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator!= (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) != self; }
  1059. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator< (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) < self; }
  1060. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator<= (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) <= self; }
  1061. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator>= (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) >= self; }
  1062. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE bool operator> (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) > self; }
  1063. /***********************************************************************/
  1064. /* Reverse arithmetic operators */
  1065. /***********************************************************************/
  1066. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator+ (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) + self; }
  1067. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator- (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) - self; }
  1068. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator* (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) * self; }
  1069. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator/ (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) / self; }
  1070. ENABLE_IF_INTEGRAL(T) ALWAYS_INLINE Decimal operator% (const T& other, const Decimal& self) { ASSERT_INTEGRAL(T); return Decimal(other) % self; }
  1071. #undef IMPORTEXPORT
  1072. #undef ALWAYS_INLINE
  1073. #undef INT64_SUBSET
  1074. #undef UINT64_SUBSET
  1075. #undef ENABLE_IF_SIGNED
  1076. #undef ENABLE_IF_UNSIGNED
  1077. #undef ENABLE_IF_INTEGRAL
  1078. #undef ASSERT_SIGNED
  1079. #undef ASSERT_UNSIGNED
  1080. #undef ASSERT_INTEGRAL
  1081. } // namespace decimal
  1082. #endif // LIBMPDECXX_DECIMAL_HH_