extract out isl_union_macro.h
[isl.git] / isl_int_sioimath.h
blob91bec90594f39315cfa454515a97c3b6c9768224
1 /*
2 * Copyright 2015 INRIA Paris-Rocquencourt
4 * Use of this software is governed by the MIT license
6 * Written by Michael Kruse, INRIA Paris-Rocquencourt,
7 * Domaine de Voluceau, Rocquenqourt, B.P. 105,
8 * 78153 Le Chesnay Cedex France
9 */
10 #ifndef ISL_INT_SIOIMATH_H
11 #define ISL_INT_SIOIMATH_H
13 #include <inttypes.h>
14 #include <limits.h>
15 #include <stdint.h>
16 #include <stdlib.h>
18 #include <isl_imath.h>
19 #include <isl/hash.h>
21 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
23 /* The type to represent integers optimized for small values. It is either a
24 * pointer to an mp_int ( = mpz_t*; big representation) or an int32_t (small
25 * represenation) with a discriminator at the least significant bit. In big
26 * representation it will be always zero because of heap alignment. It is set
27 * to 1 for small representation and use the 32 most significant bits for the
28 * int32_t.
30 * Structure on 64 bit machines, with 8-byte aligment (3 bits):
32 * Big representation:
33 * MSB LSB
34 * |------------------------------------------------------------000
35 * | mpz_t* |
36 * | != NULL |
38 * Small representation:
39 * MSB 32 LSB
40 * |------------------------------|00000000000000000000000000000001
41 * | int32_t |
42 * | 2147483647 ... -2147483647 |
43 * ^
44 * |
45 * discriminator bit
47 * On 32 bit machines isl_sioimath type is blown up to 8 bytes, i.e.
48 * isl_sioimath is guaranteed to be at least 8 bytes. This is to ensure the
49 * int32_t can be hidden in that type without data loss. In the future we might
50 * optimize this to use 31 hidden bits in a 32 bit pointer. We may also use 63
51 * bits on 64 bit machines, but this comes with the cost of additional overflow
52 * checks because there is no standardized 128 bit integer we could expand to.
54 * We use native integer types and avoid union structures to avoid assumptions
55 * on the machine's endianness.
57 * This implementation makes the following assumptions:
58 * - long can represent any int32_t
59 * - mp_small is signed long
60 * - mp_usmall is unsigned long
61 * - adresses returned by malloc are aligned to 2-byte boundaries (leastmost
62 * bit is zero)
64 #if UINT64_MAX > UINTPTR_MAX
65 typedef uint64_t isl_sioimath;
66 #else
67 typedef uintptr_t isl_sioimath;
68 #endif
70 /* The negation of the smallest possible number in int32_t, INT32_MIN
71 * (0x80000000u, -2147483648), cannot be represented in an int32_t, therefore
72 * every operation that may produce this value needs to special-case it.
73 * The operations are:
74 * abs(INT32_MIN)
75 * -INT32_MIN (negation)
76 * -1 * INT32_MIN (multiplication)
77 * INT32_MIN/-1 (any division: divexact, fdiv, cdiv, tdiv)
78 * To avoid checking these cases, we exclude INT32_MIN from small
79 * representation.
81 #define ISL_SIOIMATH_SMALL_MIN (-INT32_MAX)
83 /* Largest possible number in small representation */
84 #define ISL_SIOIMATH_SMALL_MAX INT32_MAX
86 /* Used for function parameters the function modifies. */
87 typedef isl_sioimath *isl_sioimath_ptr;
89 /* Used for function parameters that are read-only. */
90 typedef isl_sioimath isl_sioimath_src;
92 /* Return whether the argument is stored in small representation.
94 inline int isl_sioimath_is_small(isl_sioimath val)
96 return val & 0x00000001;
99 /* Return whether the argument is stored in big representation.
101 inline int isl_sioimath_is_big(isl_sioimath val)
103 return !isl_sioimath_is_small(val);
106 /* Get the number of an isl_int in small representation. Result is undefined if
107 * val is not stored in that format.
109 inline int32_t isl_sioimath_get_small(isl_sioimath val)
111 return val >> 32;
114 /* Get the number of an in isl_int in big representation. Result is undefined if
115 * val is not stored in that format.
117 inline mp_int isl_sioimath_get_big(isl_sioimath val)
119 return (mp_int)(uintptr_t) val;
122 /* Return 1 if val is stored in small representation and store its value to
123 * small. We rely on the compiler to optimize the isl_sioimath_get_small such
124 * that the shift is moved into the branch that executes in case of small
125 * representation. If there is no such branch, then a single shift is still
126 * cheaper than introducing branching code.
128 inline int isl_sioimath_decode_small(isl_sioimath val, int32_t *small)
130 *small = isl_sioimath_get_small(val);
131 return isl_sioimath_is_small(val);
134 /* Return 1 if val is stored in big representation and store its value to big.
136 inline int isl_sioimath_decode_big(isl_sioimath val, mp_int *big)
138 *big = isl_sioimath_get_big(val);
139 return isl_sioimath_is_big(val);
142 /* Encode a small representation into an isl_int.
144 inline isl_sioimath isl_sioimath_encode_small(int32_t val)
146 return ((isl_sioimath) val) << 32 | 0x00000001;
149 /* Encode a big representation.
151 inline isl_sioimath isl_sioimath_encode_big(mp_int val)
153 return (isl_sioimath)(uintptr_t) val;
156 /* A common situation is to call an IMath function with at least one argument
157 * that is currently in small representation or an integer parameter, i.e. a big
158 * representation of the same number is required. Promoting the original
159 * argument comes with multiple problems, such as modifying a read-only
160 * argument, the responsibility of deallocation and the execution cost. Instead,
161 * we make a copy by 'faking' the IMath internal structure.
163 * We reserve the maximum number of required digits on the stack to avoid heap
164 * allocations.
166 * mp_digit can be uint32_t or uint16_t. This code must work for little and big
167 * endian digits. The structure for an uint64_t argument and 32-bit mp_digits is
168 * sketched below.
170 * |----------------------------|
171 * uint64_t
173 * |-------------||-------------|
174 * mp_digit mp_digit
175 * digits[1] digits[0]
176 * Most sig digit Least sig digit
178 typedef struct {
179 mpz_t big;
180 mp_digit digits[(sizeof(uintmax_t) + sizeof(mp_digit) - 1) /
181 sizeof(mp_digit)];
182 } isl_sioimath_scratchspace_t;
184 /* Convert a native integer to IMath's digit representation. A native integer
185 * might be big- or little endian, but IMath always stores the least significant
186 * digit in the lowest array indices. memcpy therefore is not possible.
188 * We also have to consider that long and mp_digit can be of different sizes,
189 * depending on the compiler (LP64, LLP64) and IMath's USE_64BIT_WORDS. This
190 * macro should work for all of them.
192 * "used" is set to the number of written digits. It must be minimal (IMath
193 * checks zeroness using the used field), but always at least one. Also note
194 * that the result of num>>(sizeof(num)*CHAR_BIT) is undefined.
196 #define ISL_SIOIMATH_TO_DIGITS(num, digits, used) \
197 do { \
198 int i = 0; \
199 do { \
200 (digits)[i] = \
201 ((num) >> (sizeof(mp_digit) * CHAR_BIT * i)); \
202 i += 1; \
203 if (i >= (sizeof(num) + sizeof(mp_digit) - 1) / \
204 sizeof(mp_digit)) \
205 break; \
206 if (((num) >> (sizeof(mp_digit) * CHAR_BIT * i)) == 0) \
207 break; \
208 } while (1); \
209 (used) = i; \
210 } while (0)
212 inline void isl_siomath_uint32_to_digits(uint32_t num, mp_digit *digits,
213 mp_size *used)
215 ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
218 inline void isl_siomath_ulong_to_digits(unsigned long num, mp_digit *digits,
219 mp_size *used)
221 ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
224 inline void isl_siomath_uint64_to_digits(uint64_t num, mp_digit *digits,
225 mp_size *used)
227 ISL_SIOIMATH_TO_DIGITS(num, digits, *used);
230 /* Get the IMath representation of an isl_int without modifying it.
231 * For the case it is not in big representation yet, pass some scratch space we
232 * can use to store the big representation in.
233 * In order to avoid requiring init and free on the scratch space, we directly
234 * modify the internal representation.
236 * The name derives from its indented use: getting the big representation of an
237 * input (src) argument.
239 inline mp_int isl_sioimath_bigarg_src(isl_sioimath arg,
240 isl_sioimath_scratchspace_t *scratch)
242 mp_int big;
243 int32_t small;
244 uint32_t num;
246 if (isl_sioimath_decode_big(arg, &big))
247 return big;
249 small = isl_sioimath_get_small(arg);
250 scratch->big.digits = scratch->digits;
251 scratch->big.alloc = ARRAY_SIZE(scratch->digits);
252 if (small >= 0) {
253 scratch->big.sign = MP_ZPOS;
254 num = small;
255 } else {
256 scratch->big.sign = MP_NEG;
257 num = -small;
260 isl_siomath_uint32_to_digits(num, scratch->digits, &scratch->big.used);
261 return &scratch->big;
264 /* Create a temporary IMath mp_int for a signed long.
266 inline mp_int isl_sioimath_siarg_src(signed long arg,
267 isl_sioimath_scratchspace_t *scratch)
269 unsigned long num;
271 scratch->big.digits = scratch->digits;
272 scratch->big.alloc = ARRAY_SIZE(scratch->digits);
273 if (arg >= 0) {
274 scratch->big.sign = MP_ZPOS;
275 num = arg;
276 } else {
277 scratch->big.sign = MP_NEG;
278 num = (arg == LONG_MIN) ? ((unsigned long) LONG_MAX) + 1 : -arg;
281 isl_siomath_ulong_to_digits(num, scratch->digits, &scratch->big.used);
282 return &scratch->big;
285 /* Create a temporary IMath mp_int for an int64_t.
287 inline mp_int isl_sioimath_si64arg_src(int64_t arg,
288 isl_sioimath_scratchspace_t *scratch)
290 uint64_t num;
292 scratch->big.digits = scratch->digits;
293 scratch->big.alloc = ARRAY_SIZE(scratch->digits);
294 if (arg >= 0) {
295 scratch->big.sign = MP_ZPOS;
296 num = arg;
297 } else {
298 scratch->big.sign = MP_NEG;
299 num = (arg == INT64_MIN) ? ((uint64_t) INT64_MAX) + 1 : -arg;
302 isl_siomath_uint64_to_digits(num, scratch->digits, &scratch->big.used);
303 return &scratch->big;
306 /* Create a temporary IMath mp_int for an unsigned long.
308 inline mp_int isl_sioimath_uiarg_src(unsigned long arg,
309 isl_sioimath_scratchspace_t *scratch)
311 scratch->big.digits = scratch->digits;
312 scratch->big.alloc = ARRAY_SIZE(scratch->digits);
313 scratch->big.sign = MP_ZPOS;
315 isl_siomath_ulong_to_digits(arg, scratch->digits, &scratch->big.used);
316 return &scratch->big;
319 /* Ensure big representation. Does not preserve the current number.
320 * Callers may use the fact that the value _is_ preserved if the presentation
321 * was big before.
323 inline mp_int isl_sioimath_reinit_big(isl_sioimath_ptr ptr)
325 if (isl_sioimath_is_small(*ptr))
326 *ptr = isl_sioimath_encode_big(mp_int_alloc());
327 return isl_sioimath_get_big(*ptr);
330 /* Set ptr to a number in small representation.
332 inline void isl_sioimath_set_small(isl_sioimath_ptr ptr, int32_t val)
334 if (isl_sioimath_is_big(*ptr))
335 mp_int_free(isl_sioimath_get_big(*ptr));
336 *ptr = isl_sioimath_encode_small(val);
339 /* Set ptr to val, choosing small representation if possible.
341 inline void isl_sioimath_set_int32(isl_sioimath_ptr ptr, int32_t val)
343 if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
344 isl_sioimath_set_small(ptr, val);
345 return;
348 mp_int_init_value(isl_sioimath_reinit_big(ptr), val);
351 /* Assign an int64_t number using small representation if possible.
353 inline void isl_sioimath_set_int64(isl_sioimath_ptr ptr, int64_t val)
355 if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
356 isl_sioimath_set_small(ptr, val);
357 return;
360 isl_sioimath_scratchspace_t scratch;
361 mp_int_copy(isl_sioimath_si64arg_src(val, &scratch),
362 isl_sioimath_reinit_big(ptr));
365 /* Convert to big representation while preserving the current number.
367 inline void isl_sioimath_promote(isl_sioimath_ptr dst)
369 int32_t small;
371 if (isl_sioimath_is_big(*dst))
372 return;
374 small = isl_sioimath_get_small(*dst);
375 mp_int_set_value(isl_sioimath_reinit_big(dst), small);
378 /* Convert to small representation while preserving the current number. Does
379 * nothing if dst doesn't fit small representation.
381 inline void isl_sioimath_try_demote(isl_sioimath_ptr dst)
383 mp_small small;
385 if (isl_sioimath_is_small(*dst))
386 return;
388 if (mp_int_to_int(isl_sioimath_get_big(*dst), &small) != MP_OK)
389 return;
391 if (ISL_SIOIMATH_SMALL_MIN <= small && small <= ISL_SIOIMATH_SMALL_MAX)
392 isl_sioimath_set_small(dst, small);
395 /* Initialize an isl_int. The implicit value is 0 in small representation.
397 inline void isl_sioimath_init(isl_sioimath_ptr dst)
399 *dst = isl_sioimath_encode_small(0);
402 /* Free the resources taken by an isl_int.
404 inline void isl_sioimath_clear(isl_sioimath_ptr dst)
406 if (isl_sioimath_is_small(*dst))
407 return;
409 mp_int_free(isl_sioimath_get_big(*dst));
412 /* Copy the value of one isl_int to another.
414 inline void isl_sioimath_set(isl_sioimath_ptr dst, isl_sioimath_src val)
416 if (isl_sioimath_is_small(val)) {
417 isl_sioimath_set_small(dst, isl_sioimath_get_small(val));
418 return;
421 mp_int_copy(isl_sioimath_get_big(val), isl_sioimath_reinit_big(dst));
424 /* Store a signed long into an isl_int.
426 inline void isl_sioimath_set_si(isl_sioimath_ptr dst, long val)
428 if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) {
429 isl_sioimath_set_small(dst, val);
430 return;
433 mp_int_set_value(isl_sioimath_reinit_big(dst), val);
436 /* Store an unsigned long into an isl_int.
438 inline void isl_sioimath_set_ui(isl_sioimath_ptr dst, unsigned long val)
440 if (val <= ISL_SIOIMATH_SMALL_MAX) {
441 isl_sioimath_set_small(dst, val);
442 return;
445 mp_int_set_uvalue(isl_sioimath_reinit_big(dst), val);
448 /* Return whether a number can be represented by a signed long.
450 inline int isl_sioimath_fits_slong(isl_sioimath_src val)
452 mp_small dummy;
454 if (isl_sioimath_is_small(val))
455 return 1;
457 return mp_int_to_int(isl_sioimath_get_big(val), &dummy) == MP_OK;
460 /* Return a number as signed long. Result is undefined if the number cannot be
461 * represented as long.
463 inline long isl_sioimath_get_si(isl_sioimath_src val)
465 mp_small result;
467 if (isl_sioimath_is_small(val))
468 return isl_sioimath_get_small(val);
470 mp_int_to_int(isl_sioimath_get_big(val), &result);
471 return result;
474 /* Return whether a number can be represented as unsigned long.
476 inline int isl_sioimath_fits_ulong(isl_sioimath_src val)
478 mp_usmall dummy;
480 if (isl_sioimath_is_small(val))
481 return isl_sioimath_get_small(val) >= 0;
483 return mp_int_to_uint(isl_sioimath_get_big(val), &dummy) == MP_OK;
486 /* Return a number as unsigned long. Result is undefined if the number cannot be
487 * represented as unsigned long.
489 inline unsigned long isl_sioimath_get_ui(isl_sioimath_src val)
491 mp_usmall result;
493 if (isl_sioimath_is_small(val))
494 return isl_sioimath_get_small(val);
496 mp_int_to_uint(isl_sioimath_get_big(val), &result);
497 return result;
500 /* Return a number as floating point value.
502 inline double isl_sioimath_get_d(isl_sioimath_src val)
504 mp_int big;
505 double result = 0;
506 int i;
508 if (isl_sioimath_is_small(val))
509 return isl_sioimath_get_small(val);
511 big = isl_sioimath_get_big(val);
512 for (i = 0; i < big->used; ++i)
513 result = result * (double) ((uintmax_t) MP_DIGIT_MAX + 1) +
514 (double) big->digits[i];
516 if (big->sign == MP_NEG)
517 result = -result;
519 return result;
522 /* Format a number as decimal string.
524 * The largest possible string from small representation is 12 characters
525 *("-2147483647").
527 inline char *isl_sioimath_get_str(isl_sioimath_src val)
529 char *result;
531 if (isl_sioimath_is_small(val)) {
532 result = malloc(12);
533 snprintf(result, 12, "%" PRIi32, isl_sioimath_get_small(val));
534 return result;
537 return impz_get_str(NULL, 10, isl_sioimath_get_big(val));
540 /* Return the absolute value.
542 inline void isl_sioimath_abs(isl_sioimath_ptr dst, isl_sioimath_src arg)
544 if (isl_sioimath_is_small(arg)) {
545 isl_sioimath_set_small(dst, labs(isl_sioimath_get_small(arg)));
546 return;
549 mp_int_abs(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst));
552 /* Return the negation of a number.
554 inline void isl_sioimath_neg(isl_sioimath_ptr dst, isl_sioimath_src arg)
556 if (isl_sioimath_is_small(arg)) {
557 isl_sioimath_set_small(dst, -isl_sioimath_get_small(arg));
558 return;
561 mp_int_neg(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst));
564 /* Swap two isl_ints.
566 * isl_sioimath can be copied bytewise; nothing depends on its address. It can
567 * also be stored in a CPU register.
569 inline void isl_sioimath_swap(isl_sioimath_ptr lhs, isl_sioimath_ptr rhs)
571 isl_sioimath tmp = *lhs;
572 *lhs = *rhs;
573 *rhs = tmp;
576 /* Add an unsigned long to the number.
578 * On LP64 unsigned long exceeds the range of an int64_t, therefore we check in
579 * advance whether small representation possibly overflows.
581 inline void isl_sioimath_add_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
582 unsigned long rhs)
584 int32_t smalllhs;
585 isl_sioimath_scratchspace_t lhsscratch;
587 if (isl_sioimath_decode_small(lhs, &smalllhs) &&
588 (rhs <= (uint64_t) INT64_MAX - (uint64_t) ISL_SIOIMATH_SMALL_MAX)) {
589 isl_sioimath_set_int64(dst, (int64_t) smalllhs + rhs);
590 return;
593 impz_add_ui(isl_sioimath_reinit_big(dst),
594 isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs);
595 isl_sioimath_try_demote(dst);
598 /* Subtract an unsigned long.
600 * On LP64 unsigned long exceeds the range of an int64_t. If
601 * ISL_SIOIMATH_SMALL_MIN-rhs>=INT64_MIN we can do the calculation using int64_t
602 * without risking an overflow.
604 inline void isl_sioimath_sub_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
605 unsigned long rhs)
607 int32_t smalllhs;
608 isl_sioimath_scratchspace_t lhsscratch;
610 if (isl_sioimath_decode_small(lhs, &smalllhs) &&
611 (rhs < (uint64_t) INT64_MIN - (uint64_t) ISL_SIOIMATH_SMALL_MIN)) {
612 isl_sioimath_set_int64(dst, (int64_t) smalllhs - rhs);
613 return;
616 impz_sub_ui(isl_sioimath_reinit_big(dst),
617 isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs);
618 isl_sioimath_try_demote(dst);
621 /* Sum of two isl_ints.
623 inline void isl_sioimath_add(isl_sioimath_ptr dst, isl_sioimath_src lhs,
624 isl_sioimath_src rhs)
626 isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
627 int32_t smalllhs, smallrhs;
629 if (isl_sioimath_decode_small(lhs, &smalllhs) &&
630 isl_sioimath_decode_small(rhs, &smallrhs)) {
631 isl_sioimath_set_int64(
632 dst, (int64_t) smalllhs + (int64_t) smallrhs);
633 return;
636 mp_int_add(isl_sioimath_bigarg_src(lhs, &scratchlhs),
637 isl_sioimath_bigarg_src(rhs, &scratchrhs),
638 isl_sioimath_reinit_big(dst));
639 isl_sioimath_try_demote(dst);
642 /* Subtract two isl_ints.
644 inline void isl_sioimath_sub(isl_sioimath_ptr dst, isl_sioimath_src lhs,
645 isl_sioimath_src rhs)
647 isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
648 int32_t smalllhs, smallrhs;
650 if (isl_sioimath_decode_small(lhs, &smalllhs) &&
651 isl_sioimath_decode_small(rhs, &smallrhs)) {
652 isl_sioimath_set_int64(
653 dst, (int64_t) smalllhs - (int64_t) smallrhs);
654 return;
657 mp_int_sub(isl_sioimath_bigarg_src(lhs, &scratchlhs),
658 isl_sioimath_bigarg_src(rhs, &scratchrhs),
659 isl_sioimath_reinit_big(dst));
660 isl_sioimath_try_demote(dst);
663 /* Multiply two isl_ints.
665 inline void isl_sioimath_mul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
666 isl_sioimath_src rhs)
668 isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
669 int32_t smalllhs, smallrhs;
671 if (isl_sioimath_decode_small(lhs, &smalllhs) &&
672 isl_sioimath_decode_small(rhs, &smallrhs)) {
673 isl_sioimath_set_int64(
674 dst, (int64_t) smalllhs * (int64_t) smallrhs);
675 return;
678 mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
679 isl_sioimath_bigarg_src(rhs, &scratchrhs),
680 isl_sioimath_reinit_big(dst));
681 isl_sioimath_try_demote(dst);
684 /* Shift lhs by rhs bits to the left and store the result in dst. Effectively,
685 * this operation computes 'lhs * 2^rhs'.
687 inline void isl_sioimath_mul_2exp(isl_sioimath_ptr dst, isl_sioimath lhs,
688 unsigned long rhs)
690 isl_sioimath_scratchspace_t scratchlhs;
691 int32_t smalllhs;
693 if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= 32ul)) {
694 isl_sioimath_set_int64(dst, ((int64_t) smalllhs) << rhs);
695 return;
698 mp_int_mul_pow2(isl_sioimath_bigarg_src(lhs, &scratchlhs), rhs,
699 isl_sioimath_reinit_big(dst));
702 /* Multiply an isl_int and a signed long.
704 inline void isl_sioimath_mul_si(isl_sioimath_ptr dst, isl_sioimath lhs,
705 signed long rhs)
707 isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
708 int32_t smalllhs;
710 if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs > LONG_MIN) &&
711 (labs(rhs) <= UINT32_MAX)) {
712 isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs);
713 return;
716 mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
717 isl_sioimath_siarg_src(rhs, &scratchrhs),
718 isl_sioimath_reinit_big(dst));
719 isl_sioimath_try_demote(dst);
722 /* Multiply an isl_int and an unsigned long
724 inline void isl_sioimath_mul_ui(isl_sioimath_ptr dst, isl_sioimath lhs,
725 unsigned long rhs)
727 isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
728 int32_t smalllhs;
730 if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= UINT32_MAX)) {
731 isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs);
732 return;
735 mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs),
736 isl_sioimath_uiarg_src(rhs, &scratchrhs),
737 isl_sioimath_reinit_big(dst));
738 isl_sioimath_try_demote(dst);
741 /* Compute the power of an isl_int to an unsigned long.
742 * Always let IMath do it; the result is unlikely to be small except some
743 * special
744 * cases.
745 * Note: 0^0 == 1
747 inline void isl_sioimath_pow_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
748 unsigned long rhs)
750 isl_sioimath_scratchspace_t scratchlhs, scratchrhs;
751 int32_t smalllhs;
753 switch (rhs) {
754 case 0:
755 isl_sioimath_set_small(dst, 1);
756 return;
757 case 1:
758 isl_sioimath_set(dst, lhs);
759 return;
760 case 2:
761 isl_sioimath_mul(dst, lhs, lhs);
762 return;
765 if (isl_sioimath_decode_small(lhs, &smalllhs)) {
766 switch (smalllhs) {
767 case 0:
768 isl_sioimath_set_small(dst, 0);
769 return;
770 case 1:
771 isl_sioimath_set_small(dst, 1);
772 return;
773 case 2:
774 isl_sioimath_set_small(dst, 1);
775 isl_sioimath_mul_2exp(dst, *dst, rhs);
776 return;
777 default:
778 if ((MP_SMALL_MIN <= rhs) && (rhs <= MP_SMALL_MAX)) {
779 mp_int_expt_value(smalllhs, rhs,
780 isl_sioimath_reinit_big(dst));
781 isl_sioimath_try_demote(dst);
782 return;
787 mp_int_expt_full(isl_sioimath_bigarg_src(lhs, &scratchlhs),
788 isl_sioimath_uiarg_src(rhs, &scratchrhs),
789 isl_sioimath_reinit_big(dst));
790 isl_sioimath_try_demote(dst);
793 /* Fused multiply-add.
795 inline void isl_sioimath_addmul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
796 isl_sioimath_src rhs)
798 isl_sioimath tmp;
799 isl_sioimath_init(&tmp);
800 isl_sioimath_mul(&tmp, lhs, rhs);
801 isl_sioimath_add(dst, *dst, tmp);
802 isl_sioimath_clear(&tmp);
805 /* Fused multiply-add with an unsigned long.
807 inline void isl_sioimath_addmul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
808 unsigned long rhs)
810 isl_sioimath tmp;
811 isl_sioimath_init(&tmp);
812 isl_sioimath_mul_ui(&tmp, lhs, rhs);
813 isl_sioimath_add(dst, *dst, tmp);
814 isl_sioimath_clear(&tmp);
817 /* Fused multiply-subtract.
819 inline void isl_sioimath_submul(isl_sioimath_ptr dst, isl_sioimath_src lhs,
820 isl_sioimath_src rhs)
822 isl_sioimath tmp;
823 isl_sioimath_init(&tmp);
824 isl_sioimath_mul(&tmp, lhs, rhs);
825 isl_sioimath_sub(dst, *dst, tmp);
826 isl_sioimath_clear(&tmp);
829 /* Fused multiply-add with an unsigned long.
831 inline void isl_sioimath_submul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
832 unsigned long rhs)
834 isl_sioimath tmp;
835 isl_sioimath_init(&tmp);
836 isl_sioimath_mul_ui(&tmp, lhs, rhs);
837 isl_sioimath_sub(dst, *dst, tmp);
838 isl_sioimath_clear(&tmp);
841 void isl_sioimath_gcd(isl_sioimath_ptr dst, isl_sioimath_src lhs,
842 isl_sioimath_src rhs);
843 void isl_sioimath_lcm(isl_sioimath_ptr dst, isl_sioimath_src lhs,
844 isl_sioimath_src rhs);
846 /* Divide lhs by rhs, rounding to zero (Truncate).
848 inline void isl_sioimath_tdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
849 isl_sioimath_src rhs)
851 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
852 int32_t lhssmall, rhssmall;
854 if (isl_sioimath_decode_small(lhs, &lhssmall) &&
855 isl_sioimath_decode_small(rhs, &rhssmall)) {
856 isl_sioimath_set_small(dst, lhssmall / rhssmall);
857 return;
860 mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
861 isl_sioimath_bigarg_src(rhs, &rhsscratch),
862 isl_sioimath_reinit_big(dst), NULL);
863 isl_sioimath_try_demote(dst);
864 return;
867 /* Divide lhs by an unsigned long rhs, rounding to zero (Truncate).
869 inline void isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
870 unsigned long rhs)
872 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
873 int32_t lhssmall;
875 if (isl_sioimath_is_small(lhs) && (rhs <= (unsigned long) INT32_MAX)) {
876 lhssmall = isl_sioimath_get_small(lhs);
877 isl_sioimath_set_small(dst, lhssmall / (int32_t) rhs);
878 return;
881 if (rhs <= MP_SMALL_MAX) {
882 mp_int_div_value(isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs,
883 isl_sioimath_reinit_big(dst), NULL);
884 isl_sioimath_try_demote(dst);
885 return;
888 mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
889 isl_sioimath_uiarg_src(rhs, &rhsscratch),
890 isl_sioimath_reinit_big(dst), NULL);
891 isl_sioimath_try_demote(dst);
894 /* Divide lhs by rhs, rounding to positive infinity (Ceil).
896 inline void isl_sioimath_cdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
897 isl_sioimath_src rhs)
899 int32_t lhssmall, rhssmall;
900 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
901 int32_t q;
903 if (isl_sioimath_decode_small(lhs, &lhssmall) &&
904 isl_sioimath_decode_small(rhs, &rhssmall)) {
905 if ((lhssmall >= 0) && (rhssmall >= 0))
906 q = ((int64_t) lhssmall + (int64_t) rhssmall - 1) /
907 rhssmall;
908 else if ((lhssmall < 0) && (rhssmall < 0))
909 q = ((int64_t) lhssmall + (int64_t) rhssmall + 1) /
910 rhssmall;
911 else
912 q = lhssmall / rhssmall;
913 isl_sioimath_set_small(dst, q);
914 return;
917 impz_cdiv_q(isl_sioimath_reinit_big(dst),
918 isl_sioimath_bigarg_src(lhs, &lhsscratch),
919 isl_sioimath_bigarg_src(rhs, &rhsscratch));
920 isl_sioimath_try_demote(dst);
923 /* Divide lhs by rhs, rounding to negative infinity (Floor).
925 inline void isl_sioimath_fdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs,
926 isl_sioimath_src rhs)
928 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
929 int32_t lhssmall, rhssmall;
930 int32_t q;
932 if (isl_sioimath_decode_small(lhs, &lhssmall) &&
933 isl_sioimath_decode_small(rhs, &rhssmall)) {
934 if ((lhssmall < 0) && (rhssmall >= 0))
935 q = ((int64_t) lhssmall - ((int64_t) rhssmall - 1)) /
936 rhssmall;
937 else if ((lhssmall >= 0) && (rhssmall < 0))
938 q = ((int64_t) lhssmall - ((int64_t) rhssmall + 1)) /
939 rhssmall;
940 else
941 q = lhssmall / rhssmall;
942 isl_sioimath_set_small(dst, q);
943 return;
946 impz_fdiv_q(isl_sioimath_reinit_big(dst),
947 isl_sioimath_bigarg_src(lhs, &lhsscratch),
948 isl_sioimath_bigarg_src(rhs, &rhsscratch));
949 isl_sioimath_try_demote(dst);
952 /* Compute the division of lhs by a rhs of type unsigned long, rounding towards
953 * negative infinity (Floor).
955 inline void isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs,
956 unsigned long rhs)
958 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
959 int32_t lhssmall, q;
961 if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)) {
962 if (lhssmall >= 0)
963 q = (uint32_t) lhssmall / rhs;
964 else
965 q = ((int64_t) lhssmall - ((int64_t) rhs - 1)) /
966 (int64_t) rhs;
967 isl_sioimath_set_small(dst, q);
968 return;
971 impz_fdiv_q(isl_sioimath_reinit_big(dst),
972 isl_sioimath_bigarg_src(lhs, &lhsscratch),
973 isl_sioimath_uiarg_src(rhs, &rhsscratch));
974 isl_sioimath_try_demote(dst);
977 /* Get the remainder of: lhs divided by rhs rounded towards negative infinite
978 * (Floor).
980 inline void isl_sioimath_fdiv_r(isl_sioimath_ptr dst, isl_sioimath_src lhs,
981 isl_sioimath_src rhs)
983 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
984 int64_t lhssmall, rhssmall;
985 int32_t r;
987 if (isl_sioimath_is_small(lhs) && isl_sioimath_is_small(rhs)) {
988 lhssmall = isl_sioimath_get_small(lhs);
989 rhssmall = isl_sioimath_get_small(rhs);
990 r = (rhssmall + lhssmall % rhssmall) % rhssmall;
991 isl_sioimath_set_small(dst, r);
992 return;
995 impz_fdiv_r(isl_sioimath_reinit_big(dst),
996 isl_sioimath_bigarg_src(lhs, &lhsscratch),
997 isl_sioimath_bigarg_src(rhs, &rhsscratch));
998 isl_sioimath_try_demote(dst);
1001 void isl_sioimath_read(isl_sioimath_ptr dst, const char *str);
1003 /* Return:
1004 * +1 for a positive number
1005 * -1 for a negative number
1006 * 0 if the number is zero
1008 inline int isl_sioimath_sgn(isl_sioimath_src arg)
1010 int32_t small;
1012 if (isl_sioimath_decode_small(arg, &small))
1013 return (small > 0) - (small < 0);
1015 return mp_int_compare_zero(isl_sioimath_get_big(arg));
1018 /* Return:
1019 * +1 if lhs > rhs
1020 * -1 if lhs < rhs
1021 * 0 if lhs = rhs
1023 inline int isl_sioimath_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs)
1025 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
1026 int32_t lhssmall, rhssmall;
1028 if (isl_sioimath_decode_small(lhs, &lhssmall) &&
1029 isl_sioimath_decode_small(rhs, &rhssmall))
1030 return (lhssmall > rhssmall) - (lhssmall < rhssmall);
1032 if (isl_sioimath_decode_small(rhs, &rhssmall))
1033 return mp_int_compare_value(
1034 isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall);
1036 if (isl_sioimath_decode_small(lhs, &lhssmall))
1037 return -mp_int_compare_value(
1038 isl_sioimath_bigarg_src(rhs, &rhsscratch), lhssmall);
1040 return mp_int_compare(
1041 isl_sioimath_get_big(lhs), isl_sioimath_get_big(rhs));
1044 /* As isl_sioimath_cmp, but with signed long rhs.
1046 inline int isl_sioimath_cmp_si(isl_sioimath_src lhs, signed long rhs)
1048 int32_t lhssmall;
1050 if (isl_sioimath_decode_small(lhs, &lhssmall))
1051 return (lhssmall > rhs) - (lhssmall < rhs);
1053 return mp_int_compare_value(isl_sioimath_get_big(lhs), rhs);
1056 /* Return:
1057 * +1 if |lhs| > |rhs|
1058 * -1 if |lhs| < |rhs|
1059 * 0 if |lhs| = |rhs|
1061 inline int isl_sioimath_abs_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs)
1063 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
1064 int32_t lhssmall, rhssmall;
1066 if (isl_sioimath_decode_small(lhs, &lhssmall) &&
1067 isl_sioimath_decode_small(rhs, &rhssmall)) {
1068 lhssmall = labs(lhssmall);
1069 rhssmall = labs(rhssmall);
1070 return (lhssmall > rhssmall) - (lhssmall < rhssmall);
1073 return mp_int_compare_unsigned(
1074 isl_sioimath_bigarg_src(lhs, &lhsscratch),
1075 isl_sioimath_bigarg_src(rhs, &rhsscratch));
1078 /* Return whether lhs is divisible by rhs.
1080 inline int isl_sioimath_is_divisible_by(isl_sioimath_src lhs,
1081 isl_sioimath_src rhs)
1083 isl_sioimath_scratchspace_t lhsscratch, rhsscratch;
1084 int32_t lhssmall, rhssmall;
1085 mpz_t rem;
1086 int cmp;
1088 if (isl_sioimath_decode_small(lhs, &lhssmall) &&
1089 isl_sioimath_decode_small(rhs, &rhssmall))
1090 return lhssmall % rhssmall == 0;
1092 if (isl_sioimath_decode_small(rhs, &rhssmall))
1093 return mp_int_divisible_value(
1094 isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall);
1096 mp_int_init(&rem);
1097 mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch),
1098 isl_sioimath_bigarg_src(rhs, &rhsscratch), NULL, &rem);
1099 cmp = mp_int_compare_zero(&rem);
1100 mp_int_clear(&rem);
1101 return cmp == 0;
1104 /* Return a hash code of an isl_sioimath.
1105 * The hash code for a number in small and big representation must be identical
1106 * on the same machine because small representation if not obligatory if fits.
1108 inline uint32_t isl_sioimath_hash(isl_sioimath_src arg, uint32_t hash)
1110 int32_t small;
1111 int i;
1112 uint32_t num;
1113 mp_digit digits[(sizeof(uint32_t) + sizeof(mp_digit) - 1) /
1114 sizeof(mp_digit)];
1115 mp_size used;
1116 const unsigned char *digitdata = (const unsigned char *) &digits;
1118 if (isl_sioimath_decode_small(arg, &small)) {
1119 if (small < 0)
1120 isl_hash_byte(hash, 0xFF);
1121 num = labs(small);
1123 isl_siomath_uint32_to_digits(num, digits, &used);
1124 for (i = 0; i < used * sizeof(mp_digit); i += 1)
1125 isl_hash_byte(hash, digitdata[i]);
1126 return hash;
1129 return isl_imath_hash(isl_sioimath_get_big(arg), hash);
1132 /* Return the number of digits in a number of the given base or more, i.e. the
1133 * string length without sign and null terminator.
1135 * Current implementation for small representation returns the maximal number
1136 * of binary digits in that representation, which can be much larger than the
1137 * smallest possible solution.
1139 inline size_t isl_sioimath_sizeinbase(isl_sioimath_src arg, int base)
1141 int32_t small;
1143 if (isl_sioimath_decode_small(arg, &small))
1144 return sizeof(int32_t) * CHAR_BIT - 1;
1146 return impz_sizeinbase(isl_sioimath_get_big(arg), base);
1149 void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width);
1150 void isl_sioimath_dump(isl_sioimath_src arg);
1152 typedef isl_sioimath isl_int;
1153 #define isl_int_init(i) isl_sioimath_init(&(i))
1154 #define isl_int_clear(i) isl_sioimath_clear(&(i))
1156 #define isl_int_set(r, i) isl_sioimath_set(&(r), i)
1157 #define isl_int_set_si(r, i) isl_sioimath_set_si(&(r), i)
1158 #define isl_int_set_ui(r, i) isl_sioimath_set_ui(&(r), i)
1159 #define isl_int_fits_slong(r) isl_sioimath_fits_slong(r)
1160 #define isl_int_get_si(r) isl_sioimath_get_si(r)
1161 #define isl_int_fits_ulong(r) isl_sioimath_fits_ulong(r)
1162 #define isl_int_get_ui(r) isl_sioimath_get_ui(r)
1163 #define isl_int_get_d(r) isl_sioimath_get_d(r)
1164 #define isl_int_get_str(r) isl_sioimath_get_str(r)
1165 #define isl_int_abs(r, i) isl_sioimath_abs(&(r), i)
1166 #define isl_int_neg(r, i) isl_sioimath_neg(&(r), i)
1167 #define isl_int_swap(i, j) isl_sioimath_swap(&(i), &(j))
1168 #define isl_int_swap_or_set(i, j) isl_sioimath_swap(&(i), &(j))
1169 #define isl_int_add_ui(r, i, j) isl_sioimath_add_ui(&(r), i, j)
1170 #define isl_int_sub_ui(r, i, j) isl_sioimath_sub_ui(&(r), i, j)
1172 #define isl_int_add(r, i, j) isl_sioimath_add(&(r), i, j)
1173 #define isl_int_sub(r, i, j) isl_sioimath_sub(&(r), i, j)
1174 #define isl_int_mul(r, i, j) isl_sioimath_mul(&(r), i, j)
1175 #define isl_int_mul_2exp(r, i, j) isl_sioimath_mul_2exp(&(r), i, j)
1176 #define isl_int_mul_si(r, i, j) isl_sioimath_mul_si(&(r), i, j)
1177 #define isl_int_mul_ui(r, i, j) isl_sioimath_mul_ui(&(r), i, j)
1178 #define isl_int_pow_ui(r, i, j) isl_sioimath_pow_ui(&(r), i, j)
1179 #define isl_int_addmul(r, i, j) isl_sioimath_addmul(&(r), i, j)
1180 #define isl_int_addmul_ui(r, i, j) isl_sioimath_addmul_ui(&(r), i, j)
1181 #define isl_int_submul(r, i, j) isl_sioimath_submul(&(r), i, j)
1182 #define isl_int_submul_ui(r, i, j) isl_sioimath_submul_ui(&(r), i, j)
1184 #define isl_int_gcd(r, i, j) isl_sioimath_gcd(&(r), i, j)
1185 #define isl_int_lcm(r, i, j) isl_sioimath_lcm(&(r), i, j)
1186 #define isl_int_divexact(r, i, j) isl_sioimath_tdiv_q(&(r), i, j)
1187 #define isl_int_divexact_ui(r, i, j) isl_sioimath_tdiv_q_ui(&(r), i, j)
1188 #define isl_int_tdiv_q(r, i, j) isl_sioimath_tdiv_q(&(r), i, j)
1189 #define isl_int_cdiv_q(r, i, j) isl_sioimath_cdiv_q(&(r), i, j)
1190 #define isl_int_fdiv_q(r, i, j) isl_sioimath_fdiv_q(&(r), i, j)
1191 #define isl_int_fdiv_r(r, i, j) isl_sioimath_fdiv_r(&(r), i, j)
1192 #define isl_int_fdiv_q_ui(r, i, j) isl_sioimath_fdiv_q_ui(&(r), i, j)
1194 #define isl_int_read(r, s) isl_sioimath_read(&(r), s)
1195 #define isl_int_sgn(i) isl_sioimath_sgn(i)
1196 #define isl_int_cmp(i, j) isl_sioimath_cmp(i, j)
1197 #define isl_int_cmp_si(i, si) isl_sioimath_cmp_si(i, si)
1198 #define isl_int_eq(i, j) (isl_sioimath_cmp(i, j) == 0)
1199 #define isl_int_ne(i, j) (isl_sioimath_cmp(i, j) != 0)
1200 #define isl_int_lt(i, j) (isl_sioimath_cmp(i, j) < 0)
1201 #define isl_int_le(i, j) (isl_sioimath_cmp(i, j) <= 0)
1202 #define isl_int_gt(i, j) (isl_sioimath_cmp(i, j) > 0)
1203 #define isl_int_ge(i, j) (isl_sioimath_cmp(i, j) >= 0)
1204 #define isl_int_abs_cmp(i, j) isl_sioimath_abs_cmp(i, j)
1205 #define isl_int_abs_eq(i, j) (isl_sioimath_abs_cmp(i, j) == 0)
1206 #define isl_int_abs_ne(i, j) (isl_sioimath_abs_cmp(i, j) != 0)
1207 #define isl_int_abs_lt(i, j) (isl_sioimath_abs_cmp(i, j) < 0)
1208 #define isl_int_abs_gt(i, j) (isl_sioimath_abs_cmp(i, j) > 0)
1209 #define isl_int_abs_ge(i, j) (isl_sioimath_abs_cmp(i, j) >= 0)
1210 #define isl_int_is_divisible_by(i, j) isl_sioimath_is_divisible_by(i, j)
1212 #define isl_int_hash(v, h) isl_sioimath_hash(v, h)
1213 #define isl_int_free_str(s) free(s)
1214 #define isl_int_print(out, i, width) isl_sioimath_print(out, i, width)
1216 #endif /* ISL_INT_SIOIMATH_H */