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
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
_mpd_mul_words(mpd_uint_t * hi,mpd_uint_t * lo,mpd_uint_t a,mpd_uint_t b)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
_mpd_div_words(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t hi,mpd_uint_t lo,mpd_uint_t d)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
_mpd_mul_words(mpd_uint_t * hi,mpd_uint_t * lo,mpd_uint_t a,mpd_uint_t b)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
nlz(uint64_t x)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
_mpd_div_words(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t u1,mpd_uint_t u0,mpd_uint_t v)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
_mpd_mul_words(mpd_uint_t * hi,mpd_uint_t * lo,mpd_uint_t a,mpd_uint_t b)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
_mpd_div_words(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t hi,mpd_uint_t lo,mpd_uint_t d)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
_mpd_mul_words(mpd_uint_t * hi,mpd_uint_t * lo,mpd_uint_t a,mpd_uint_t b)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
_mpd_divmod_pow10(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t v,mpd_uint_t exp)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
_mpd_mul_words(mpd_uint_t * hi,mpd_uint_t * lo,mpd_uint_t a,mpd_uint_t b)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
_mpd_div_words(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t hi,mpd_uint_t lo,mpd_uint_t d)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
_mpd_mul_words(mpd_uint_t * hi,mpd_uint_t * lo,mpd_uint_t a,mpd_uint_t b)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
nlz(uint32_t x)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
_mpd_div_words(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t u1,mpd_uint_t u0,mpd_uint_t v)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
_mpd_mul_words(mpd_uint_t * hi,mpd_uint_t * lo,mpd_uint_t a,mpd_uint_t b)463 _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 __asm__ ( "mull %3\n\t"
468 : "=d" (h), "=a" (l)
469 : "%a" (a), "rm" (b)
470 : "cc"
471 );
472
473 *hi = h;
474 *lo = l;
475 }
476
477 static inline void
_mpd_div_words(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t hi,mpd_uint_t lo,mpd_uint_t d)478 _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 __asm__ ( "divl %4\n\t"
484 : "=a" (qq), "=d" (rr)
485 : "a" (lo), "d" (hi), "rm" (d)
486 : "cc"
487 );
488
489 *q = qq;
490 *r = rr;
491 }
492 /* END GCC ASM */
493 #elif defined(MASM)
494 static inline void __cdecl
_mpd_mul_words(mpd_uint_t * hi,mpd_uint_t * lo,mpd_uint_t a,mpd_uint_t b)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
_mpd_div_words(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t hi,mpd_uint_t lo,mpd_uint_t d)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
_mpd_divmod_pow10(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t v,mpd_uint_t exp)534 _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 if (exp <= 4) {
539 switch (exp) {
540 case 0: *q = v; *r = 0; break;
541 case 1: DIVMOD(q, r, v, 10UL); break;
542 case 2: DIVMOD(q, r, v, 100UL); break;
543 case 3: DIVMOD(q, r, v, 1000UL); break;
544 case 4: DIVMOD(q, r, v, 10000UL); break;
545 }
546 }
547 else {
548 switch (exp) {
549 case 5: DIVMOD(q, r, v, 100000UL); break;
550 case 6: DIVMOD(q, r, v, 1000000UL); break;
551 case 7: DIVMOD(q, r, v, 10000000UL); break;
552 case 8: DIVMOD(q, r, v, 100000000UL); break;
553 case 9: DIVMOD(q, r, v, 1000000000UL); break; /* GCOV_NOT_REACHED */
554 }
555 }
556 }
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
_mpd_div_word(mpd_uint_t * q,mpd_uint_t * r,mpd_uint_t v,mpd_uint_t d)566 _mpd_div_word(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t d)
567 {
568 *q = v / d;
569 *r = v - *q * d;
570 }
571
572 static inline void
_mpd_idiv_word(mpd_ssize_t * q,mpd_ssize_t * r,mpd_ssize_t v,mpd_ssize_t d)573 _mpd_idiv_word(mpd_ssize_t *q, mpd_ssize_t *r, mpd_ssize_t v, mpd_ssize_t d)
574 {
575 *q = v / d;
576 *r = v - *q * d;
577 }
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
add_size_t(mpd_size_t a,mpd_size_t b)592 add_size_t(mpd_size_t a, mpd_size_t b)
593 {
594 if (a > MPD_SIZE_MAX - b) {
595 mpd_err_fatal("add_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
596 }
597 return a + b;
598 }
599
600 static inline mpd_size_t
sub_size_t(mpd_size_t a,mpd_size_t b)601 sub_size_t(mpd_size_t a, mpd_size_t b)
602 {
603 if (b > a) {
604 mpd_err_fatal("sub_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
605 }
606 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
mul_size_t(mpd_size_t a,mpd_size_t b)614 mul_size_t(mpd_size_t a, mpd_size_t b)
615 {
616 mpd_uint_t hi, lo;
617
618 _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b);
619 if (hi) {
620 mpd_err_fatal("mul_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */
621 }
622 return lo;
623 }
624
625 static inline mpd_size_t
add_size_t_overflow(mpd_size_t a,mpd_size_t b,mpd_size_t * overflow)626 add_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow)
627 {
628 mpd_size_t ret;
629
630 *overflow = 0;
631 ret = a + b;
632 if (ret < a) *overflow = 1;
633 return ret;
634 }
635
636 static inline mpd_size_t
mul_size_t_overflow(mpd_size_t a,mpd_size_t b,mpd_size_t * overflow)637 mul_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow)
638 {
639 mpd_uint_t lo;
640
641 _mpd_mul_words((mpd_uint_t *)overflow, &lo, (mpd_uint_t)a,
642 (mpd_uint_t)b);
643 return lo;
644 }
645
646 static inline mpd_ssize_t
mod_mpd_ssize_t(mpd_ssize_t a,mpd_ssize_t m)647 mod_mpd_ssize_t(mpd_ssize_t a, mpd_ssize_t m)
648 {
649 mpd_ssize_t r = a % m;
650 return (r < 0) ? r + m : r;
651 }
652
653 static inline mpd_size_t
mulmod_size_t(mpd_size_t a,mpd_size_t b,mpd_size_t m)654 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 _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b);
660 _mpd_div_words(&q, &r, hi, lo, (mpd_uint_t)m);
661
662 return r;
663 }
664
665
666 #endif /* TYPEARITH_H */
667
668
669
670