typearith.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. /*
  2. * Copyright (c) 2008-2016 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 TYPEARITH_H
  28. #define TYPEARITH_H
  29. #include "mpdecimal.h"
  30. /*****************************************************************************/
  31. /* Low level native arithmetic on basic types */
  32. /*****************************************************************************/
  33. /** ------------------------------------------------------------
  34. ** Double width multiplication and division
  35. ** ------------------------------------------------------------
  36. */
  37. #if defined(CONFIG_64)
  38. #if defined(ANSI)
  39. #if defined(HAVE_UINT128_T)
  40. static inline void
  41. _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
  42. {
  43. __uint128_t hl;
  44. hl = (__uint128_t)a * b;
  45. *hi = hl >> 64;
  46. *lo = (mpd_uint_t)hl;
  47. }
  48. static inline void
  49. _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
  50. mpd_uint_t d)
  51. {
  52. __uint128_t hl;
  53. hl = ((__uint128_t)hi<<64) + lo;
  54. *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */
  55. *r = (mpd_uint_t)(hl - (__uint128_t)(*q) * d);
  56. }
  57. #else
  58. static inline void
  59. _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
  60. {
  61. uint32_t w[4], carry;
  62. uint32_t ah, al, bh, bl;
  63. uint64_t hl;
  64. ah = (uint32_t)(a>>32); al = (uint32_t)a;
  65. bh = (uint32_t)(b>>32); bl = (uint32_t)b;
  66. hl = (uint64_t)al * bl;
  67. w[0] = (uint32_t)hl;
  68. carry = (uint32_t)(hl>>32);
  69. hl = (uint64_t)ah * bl + carry;
  70. w[1] = (uint32_t)hl;
  71. w[2] = (uint32_t)(hl>>32);
  72. hl = (uint64_t)al * bh + w[1];
  73. w[1] = (uint32_t)hl;
  74. carry = (uint32_t)(hl>>32);
  75. hl = ((uint64_t)ah * bh + w[2]) + carry;
  76. w[2] = (uint32_t)hl;
  77. w[3] = (uint32_t)(hl>>32);
  78. *hi = ((uint64_t)w[3]<<32) + w[2];
  79. *lo = ((uint64_t)w[1]<<32) + w[0];
  80. }
  81. /*
  82. * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt
  83. * http://www.hackersdelight.org/permissions.htm:
  84. * "You are free to use, copy, and distribute any of the code on this web
  85. * site, whether modified by you or not. You need not give attribution."
  86. *
  87. * Slightly modified, comments are mine.
  88. */
  89. static inline int
  90. nlz(uint64_t x)
  91. {
  92. int n;
  93. if (x == 0) return(64);
  94. n = 0;
  95. if (x <= 0x00000000FFFFFFFF) {n = n +32; x = x <<32;}
  96. if (x <= 0x0000FFFFFFFFFFFF) {n = n +16; x = x <<16;}
  97. if (x <= 0x00FFFFFFFFFFFFFF) {n = n + 8; x = x << 8;}
  98. if (x <= 0x0FFFFFFFFFFFFFFF) {n = n + 4; x = x << 4;}
  99. if (x <= 0x3FFFFFFFFFFFFFFF) {n = n + 2; x = x << 2;}
  100. if (x <= 0x7FFFFFFFFFFFFFFF) {n = n + 1;}
  101. return n;
  102. }
  103. static inline void
  104. _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0,
  105. mpd_uint_t v)
  106. {
  107. const mpd_uint_t b = 4294967296;
  108. mpd_uint_t un1, un0,
  109. vn1, vn0,
  110. q1, q0,
  111. un32, un21, un10,
  112. rhat, t;
  113. int s;
  114. assert(u1 < v);
  115. s = nlz(v);
  116. v = v << s;
  117. vn1 = v >> 32;
  118. vn0 = v & 0xFFFFFFFF;
  119. t = (s == 0) ? 0 : u0 >> (64 - s);
  120. un32 = (u1 << s) | t;
  121. un10 = u0 << s;
  122. un1 = un10 >> 32;
  123. un0 = un10 & 0xFFFFFFFF;
  124. q1 = un32 / vn1;
  125. rhat = un32 - q1*vn1;
  126. again1:
  127. if (q1 >= b || q1*vn0 > b*rhat + un1) {
  128. q1 = q1 - 1;
  129. rhat = rhat + vn1;
  130. if (rhat < b) goto again1;
  131. }
  132. /*
  133. * Before again1 we had:
  134. * (1) q1*vn1 + rhat = un32
  135. * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1
  136. *
  137. * The statements inside the if-clause do not change the value
  138. * of the left-hand side of (2), and the loop is only exited
  139. * if q1*vn0 <= rhat*b + un1, so:
  140. *
  141. * (3) q1*vn1*b + q1*vn0 <= un32*b + un1
  142. * (4) q1*v <= un32*b + un1
  143. * (5) 0 <= un32*b + un1 - q1*v
  144. *
  145. * By (5) we are certain that the possible add-back step from
  146. * Knuth's algorithm D is never required.
  147. *
  148. * Since the final quotient is less than 2**64, the following
  149. * must be true:
  150. *
  151. * (6) un32*b + un1 - q1*v <= UINT64_MAX
  152. *
  153. * This means that in the following line, the high words
  154. * of un32*b and q1*v can be discarded without any effect
  155. * on the result.
  156. */
  157. un21 = un32*b + un1 - q1*v;
  158. q0 = un21 / vn1;
  159. rhat = un21 - q0*vn1;
  160. again2:
  161. if (q0 >= b || q0*vn0 > b*rhat + un0) {
  162. q0 = q0 - 1;
  163. rhat = rhat + vn1;
  164. if (rhat < b) goto again2;
  165. }
  166. *q = q1*b + q0;
  167. *r = (un21*b + un0 - q0*v) >> s;
  168. }
  169. #endif
  170. /* END ANSI */
  171. #elif defined(ASM)
  172. static inline void
  173. _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
  174. {
  175. mpd_uint_t h, l;
  176. __asm__ ( "mulq %3\n\t"
  177. : "=d" (h), "=a" (l)
  178. : "%a" (a), "rm" (b)
  179. : "cc"
  180. );
  181. *hi = h;
  182. *lo = l;
  183. }
  184. static inline void
  185. _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
  186. mpd_uint_t d)
  187. {
  188. mpd_uint_t qq, rr;
  189. __asm__ ( "divq %4\n\t"
  190. : "=a" (qq), "=d" (rr)
  191. : "a" (lo), "d" (hi), "rm" (d)
  192. : "cc"
  193. );
  194. *q = qq;
  195. *r = rr;
  196. }
  197. /* END GCC ASM */
  198. #elif defined(MASM)
  199. #include <intrin.h>
  200. #pragma intrinsic(_umul128)
  201. static inline void
  202. _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
  203. {
  204. *lo = _umul128(a, b, hi);
  205. }
  206. void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
  207. mpd_uint_t d);
  208. /* END MASM (_MSC_VER) */
  209. #else
  210. #error "need platform specific 128 bit multiplication and division"
  211. #endif
  212. #define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d
  213. static inline void
  214. _mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp)
  215. {
  216. assert(exp <= 19);
  217. if (exp <= 9) {
  218. if (exp <= 4) {
  219. switch (exp) {
  220. case 0: *q = v; *r = 0; break;
  221. case 1: DIVMOD(q, r, v, 10UL); break;
  222. case 2: DIVMOD(q, r, v, 100UL); break;
  223. case 3: DIVMOD(q, r, v, 1000UL); break;
  224. case 4: DIVMOD(q, r, v, 10000UL); break;
  225. }
  226. }
  227. else {
  228. switch (exp) {
  229. case 5: DIVMOD(q, r, v, 100000UL); break;
  230. case 6: DIVMOD(q, r, v, 1000000UL); break;
  231. case 7: DIVMOD(q, r, v, 10000000UL); break;
  232. case 8: DIVMOD(q, r, v, 100000000UL); break;
  233. case 9: DIVMOD(q, r, v, 1000000000UL); break;
  234. }
  235. }
  236. }
  237. else {
  238. if (exp <= 14) {
  239. switch (exp) {
  240. case 10: DIVMOD(q, r, v, 10000000000ULL); break;
  241. case 11: DIVMOD(q, r, v, 100000000000ULL); break;
  242. case 12: DIVMOD(q, r, v, 1000000000000ULL); break;
  243. case 13: DIVMOD(q, r, v, 10000000000000ULL); break;
  244. case 14: DIVMOD(q, r, v, 100000000000000ULL); break;
  245. }
  246. }
  247. else {
  248. switch (exp) {
  249. case 15: DIVMOD(q, r, v, 1000000000000000ULL); break;
  250. case 16: DIVMOD(q, r, v, 10000000000000000ULL); break;
  251. case 17: DIVMOD(q, r, v, 100000000000000000ULL); break;
  252. case 18: DIVMOD(q, r, v, 1000000000000000000ULL); break;
  253. case 19: DIVMOD(q, r, v, 10000000000000000000ULL); break; /* GCOV_NOT_REACHED */
  254. }
  255. }
  256. }
  257. }
  258. /* END CONFIG_64 */
  259. #elif defined(CONFIG_32)
  260. #if defined(ANSI)
  261. #if !defined(LEGACY_COMPILER)
  262. static inline void
  263. _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
  264. {
  265. mpd_uuint_t hl;
  266. hl = (mpd_uuint_t)a * b;
  267. *hi = hl >> 32;
  268. *lo = (mpd_uint_t)hl;
  269. }
  270. static inline void
  271. _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
  272. mpd_uint_t d)
  273. {
  274. mpd_uuint_t hl;
  275. hl = ((mpd_uuint_t)hi<<32) + lo;
  276. *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */
  277. *r = (mpd_uint_t)(hl - (mpd_uuint_t)(*q) * d);
  278. }
  279. /* END ANSI + uint64_t */
  280. #else
  281. static inline void
  282. _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
  283. {
  284. uint16_t w[4], carry;
  285. uint16_t ah, al, bh, bl;
  286. uint32_t hl;
  287. ah = (uint16_t)(a>>16); al = (uint16_t)a;
  288. bh = (uint16_t)(b>>16); bl = (uint16_t)b;
  289. hl = (uint32_t)al * bl;
  290. w[0] = (uint16_t)hl;
  291. carry = (uint16_t)(hl>>16);
  292. hl = (uint32_t)ah * bl + carry;
  293. w[1] = (uint16_t)hl;
  294. w[2] = (uint16_t)(hl>>16);
  295. hl = (uint32_t)al * bh + w[1];
  296. w[1] = (uint16_t)hl;
  297. carry = (uint16_t)(hl>>16);
  298. hl = ((uint32_t)ah * bh + w[2]) + carry;
  299. w[2] = (uint16_t)hl;
  300. w[3] = (uint16_t)(hl>>16);
  301. *hi = ((uint32_t)w[3]<<16) + w[2];
  302. *lo = ((uint32_t)w[1]<<16) + w[0];
  303. }
  304. /*
  305. * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt
  306. * http://www.hackersdelight.org/permissions.htm:
  307. * "You are free to use, copy, and distribute any of the code on this web
  308. * site, whether modified by you or not. You need not give attribution."
  309. *
  310. * Slightly modified, comments are mine.
  311. */
  312. static inline int
  313. nlz(uint32_t x)
  314. {
  315. int n;
  316. if (x == 0) return(32);
  317. n = 0;
  318. if (x <= 0x0000FFFF) {n = n +16; x = x <<16;}
  319. if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;}
  320. if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
  321. if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
  322. if (x <= 0x7FFFFFFF) {n = n + 1;}
  323. return n;
  324. }
  325. static inline void
  326. _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0,
  327. mpd_uint_t v)
  328. {
  329. const mpd_uint_t b = 65536;
  330. mpd_uint_t un1, un0,
  331. vn1, vn0,
  332. q1, q0,
  333. un32, un21, un10,
  334. rhat, t;
  335. int s;
  336. assert(u1 < v);
  337. s = nlz(v);
  338. v = v << s;
  339. vn1 = v >> 16;
  340. vn0 = v & 0xFFFF;
  341. t = (s == 0) ? 0 : u0 >> (32 - s);
  342. un32 = (u1 << s) | t;
  343. un10 = u0 << s;
  344. un1 = un10 >> 16;
  345. un0 = un10 & 0xFFFF;
  346. q1 = un32 / vn1;
  347. rhat = un32 - q1*vn1;
  348. again1:
  349. if (q1 >= b || q1*vn0 > b*rhat + un1) {
  350. q1 = q1 - 1;
  351. rhat = rhat + vn1;
  352. if (rhat < b) goto again1;
  353. }
  354. /*
  355. * Before again1 we had:
  356. * (1) q1*vn1 + rhat = un32
  357. * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1
  358. *
  359. * The statements inside the if-clause do not change the value
  360. * of the left-hand side of (2), and the loop is only exited
  361. * if q1*vn0 <= rhat*b + un1, so:
  362. *
  363. * (3) q1*vn1*b + q1*vn0 <= un32*b + un1
  364. * (4) q1*v <= un32*b + un1
  365. * (5) 0 <= un32*b + un1 - q1*v
  366. *
  367. * By (5) we are certain that the possible add-back step from
  368. * Knuth's algorithm D is never required.
  369. *
  370. * Since the final quotient is less than 2**32, the following
  371. * must be true:
  372. *
  373. * (6) un32*b + un1 - q1*v <= UINT32_MAX
  374. *
  375. * This means that in the following line, the high words
  376. * of un32*b and q1*v can be discarded without any effect
  377. * on the result.
  378. */
  379. un21 = un32*b + un1 - q1*v;
  380. q0 = un21 / vn1;
  381. rhat = un21 - q0*vn1;
  382. again2:
  383. if (q0 >= b || q0*vn0 > b*rhat + un0) {
  384. q0 = q0 - 1;
  385. rhat = rhat + vn1;
  386. if (rhat < b) goto again2;
  387. }
  388. *q = q1*b + q0;
  389. *r = (un21*b + un0 - q0*v) >> s;
  390. }
  391. #endif /* END ANSI + LEGACY_COMPILER */
  392. /* END ANSI */
  393. #elif defined(ASM)
  394. static inline void
  395. _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
  396. {
  397. mpd_uint_t h, l;
  398. __asm__ ( "mull %3\n\t"
  399. : "=d" (h), "=a" (l)
  400. : "%a" (a), "rm" (b)
  401. : "cc"
  402. );
  403. *hi = h;
  404. *lo = l;
  405. }
  406. static inline void
  407. _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
  408. mpd_uint_t d)
  409. {
  410. mpd_uint_t qq, rr;
  411. __asm__ ( "divl %4\n\t"
  412. : "=a" (qq), "=d" (rr)
  413. : "a" (lo), "d" (hi), "rm" (d)
  414. : "cc"
  415. );
  416. *q = qq;
  417. *r = rr;
  418. }
  419. /* END GCC ASM */
  420. #elif defined(MASM)
  421. static inline void __cdecl
  422. _mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b)
  423. {
  424. mpd_uint_t h, l;
  425. __asm {
  426. mov eax, a
  427. mul b
  428. mov h, edx
  429. mov l, eax
  430. }
  431. *hi = h;
  432. *lo = l;
  433. }
  434. static inline void __cdecl
  435. _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo,
  436. mpd_uint_t d)
  437. {
  438. mpd_uint_t qq, rr;
  439. __asm {
  440. mov eax, lo
  441. mov edx, hi
  442. div d
  443. mov qq, eax
  444. mov rr, edx
  445. }
  446. *q = qq;
  447. *r = rr;
  448. }
  449. /* END MASM (_MSC_VER) */
  450. #else
  451. #error "need platform specific 64 bit multiplication and division"
  452. #endif
  453. #define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d
  454. static inline void
  455. _mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp)
  456. {
  457. assert(exp <= 9);
  458. if (exp <= 4) {
  459. switch (exp) {
  460. case 0: *q = v; *r = 0; break;
  461. case 1: DIVMOD(q, r, v, 10UL); break;
  462. case 2: DIVMOD(q, r, v, 100UL); break;
  463. case 3: DIVMOD(q, r, v, 1000UL); break;
  464. case 4: DIVMOD(q, r, v, 10000UL); break;
  465. }
  466. }
  467. else {
  468. switch (exp) {
  469. case 5: DIVMOD(q, r, v, 100000UL); break;
  470. case 6: DIVMOD(q, r, v, 1000000UL); break;
  471. case 7: DIVMOD(q, r, v, 10000000UL); break;
  472. case 8: DIVMOD(q, r, v, 100000000UL); break;
  473. case 9: DIVMOD(q, r, v, 1000000000UL); break; /* GCOV_NOT_REACHED */
  474. }
  475. }
  476. }
  477. /* END CONFIG_32 */
  478. /* NO CONFIG */
  479. #else
  480. #error "define CONFIG_64 or CONFIG_32"
  481. #endif /* CONFIG */
  482. static inline void
  483. _mpd_div_word(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t d)
  484. {
  485. *q = v / d;
  486. *r = v - *q * d;
  487. }
  488. static inline void
  489. _mpd_idiv_word(mpd_ssize_t *q, mpd_ssize_t *r, mpd_ssize_t v, mpd_ssize_t d)
  490. {
  491. *q = v / d;
  492. *r = v - *q * d;
  493. }
  494. /** ------------------------------------------------------------
  495. ** Arithmetic with overflow checking
  496. ** ------------------------------------------------------------
  497. */
  498. /* The following macros do call exit() in case of an overflow.
  499. If the library is used correctly (i.e. with valid context
  500. parameters), such overflows cannot occur. The macros are used
  501. as sanity checks in a couple of strategic places and should
  502. be viewed as a handwritten version of gcc's -ftrapv option. */
  503. static inline mpd_size_t
  504. add_size_t(mpd_size_t a, mpd_size_t b)
  505. {
  506. if (a > MPD_SIZE_MAX - b) {
  507. mpd_err_fatal("add_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
  508. }
  509. return a + b;
  510. }
  511. static inline mpd_size_t
  512. sub_size_t(mpd_size_t a, mpd_size_t b)
  513. {
  514. if (b > a) {
  515. mpd_err_fatal("sub_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
  516. }
  517. return a - b;
  518. }
  519. #if MPD_SIZE_MAX != MPD_UINT_MAX
  520. #error "adapt mul_size_t() and mulmod_size_t()"
  521. #endif
  522. static inline mpd_size_t
  523. mul_size_t(mpd_size_t a, mpd_size_t b)
  524. {
  525. mpd_uint_t hi, lo;
  526. _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b);
  527. if (hi) {
  528. mpd_err_fatal("mul_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
  529. }
  530. return lo;
  531. }
  532. static inline mpd_size_t
  533. add_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow)
  534. {
  535. mpd_size_t ret;
  536. *overflow = 0;
  537. ret = a + b;
  538. if (ret < a) *overflow = 1;
  539. return ret;
  540. }
  541. static inline mpd_size_t
  542. mul_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow)
  543. {
  544. mpd_uint_t lo;
  545. _mpd_mul_words((mpd_uint_t *)overflow, &lo, (mpd_uint_t)a,
  546. (mpd_uint_t)b);
  547. return lo;
  548. }
  549. static inline mpd_ssize_t
  550. mod_mpd_ssize_t(mpd_ssize_t a, mpd_ssize_t m)
  551. {
  552. mpd_ssize_t r = a % m;
  553. return (r < 0) ? r + m : r;
  554. }
  555. static inline mpd_size_t
  556. mulmod_size_t(mpd_size_t a, mpd_size_t b, mpd_size_t m)
  557. {
  558. mpd_uint_t hi, lo;
  559. mpd_uint_t q, r;
  560. _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b);
  561. _mpd_div_words(&q, &r, hi, lo, (mpd_uint_t)m);
  562. return r;
  563. }
  564. #endif /* TYPEARITH_H */