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