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
10 #ifndef ISL_INT_SIOIMATH_H
11 #define ISL_INT_SIOIMATH_H
18 #include <isl_imath.h>
21 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
23 /* Visual Studio before VS2015 does not support the inline keyword when
24 * compiling in C mode because it was introduced in C99 which it does not
25 * officially support. Instead, it has a proprietary extension using __inline.
27 #if defined(_MSC_VER) && (_MSC_VER < 1900)
28 #define inline __inline
31 /* The type to represent integers optimized for small values. It is either a
32 * pointer to an mp_int ( = mpz_t*; big representation) or an int32_t (small
33 * represenation) with a discriminator at the least significant bit. In big
34 * representation it will be always zero because of heap alignment. It is set
35 * to 1 for small representation and use the 32 most significant bits for the
38 * Structure on 64 bit machines, with 8-byte aligment (3 bits):
42 * |------------------------------------------------------------000
46 * Small representation:
48 * |------------------------------|00000000000000000000000000000001
50 * | 2147483647 ... -2147483647 |
55 * On 32 bit machines isl_sioimath type is blown up to 8 bytes, i.e.
56 * isl_sioimath is guaranteed to be at least 8 bytes. This is to ensure the
57 * int32_t can be hidden in that type without data loss. In the future we might
58 * optimize this to use 31 hidden bits in a 32 bit pointer. We may also use 63
59 * bits on 64 bit machines, but this comes with the cost of additional overflow
60 * checks because there is no standardized 128 bit integer we could expand to.
62 * We use native integer types and avoid union structures to avoid assumptions
63 * on the machine's endianness.
65 * This implementation makes the following assumptions:
66 * - long can represent any int32_t
67 * - mp_small is signed long
68 * - mp_usmall is unsigned long
69 * - adresses returned by malloc are aligned to 2-byte boundaries (leastmost
72 #if UINT64_MAX > UINTPTR_MAX
73 typedef uint64_t isl_sioimath
;
75 typedef uintptr_t isl_sioimath
;
78 /* The negation of the smallest possible number in int32_t, INT32_MIN
79 * (0x80000000u, -2147483648), cannot be represented in an int32_t, therefore
80 * every operation that may produce this value needs to special-case it.
83 * -INT32_MIN (negation)
84 * -1 * INT32_MIN (multiplication)
85 * INT32_MIN/-1 (any division: divexact, fdiv, cdiv, tdiv)
86 * To avoid checking these cases, we exclude INT32_MIN from small
89 #define ISL_SIOIMATH_SMALL_MIN (-INT32_MAX)
91 /* Largest possible number in small representation */
92 #define ISL_SIOIMATH_SMALL_MAX INT32_MAX
94 /* Used for function parameters the function modifies. */
95 typedef isl_sioimath
*isl_sioimath_ptr
;
97 /* Used for function parameters that are read-only. */
98 typedef isl_sioimath isl_sioimath_src
;
100 /* Return whether the argument is stored in small representation.
102 inline int isl_sioimath_is_small(isl_sioimath val
)
104 return val
& 0x00000001;
107 /* Return whether the argument is stored in big representation.
109 inline int isl_sioimath_is_big(isl_sioimath val
)
111 return !isl_sioimath_is_small(val
);
114 /* Get the number of an isl_int in small representation. Result is undefined if
115 * val is not stored in that format.
117 inline int32_t isl_sioimath_get_small(isl_sioimath val
)
122 /* Get the number of an in isl_int in big representation. Result is undefined if
123 * val is not stored in that format.
125 inline mp_int
isl_sioimath_get_big(isl_sioimath val
)
127 return (mp_int
)(uintptr_t) val
;
130 /* Return 1 if val is stored in small representation and store its value to
131 * small. We rely on the compiler to optimize the isl_sioimath_get_small such
132 * that the shift is moved into the branch that executes in case of small
133 * representation. If there is no such branch, then a single shift is still
134 * cheaper than introducing branching code.
136 inline int isl_sioimath_decode_small(isl_sioimath val
, int32_t *small
)
138 *small
= isl_sioimath_get_small(val
);
139 return isl_sioimath_is_small(val
);
142 /* Return 1 if val is stored in big representation and store its value to big.
144 inline int isl_sioimath_decode_big(isl_sioimath val
, mp_int
*big
)
146 *big
= isl_sioimath_get_big(val
);
147 return isl_sioimath_is_big(val
);
150 /* Encode a small representation into an isl_int.
152 inline isl_sioimath
isl_sioimath_encode_small(int32_t val
)
154 return ((isl_sioimath
) val
) << 32 | 0x00000001;
157 /* Encode a big representation.
159 inline isl_sioimath
isl_sioimath_encode_big(mp_int val
)
161 return (isl_sioimath
)(uintptr_t) val
;
164 /* A common situation is to call an IMath function with at least one argument
165 * that is currently in small representation or an integer parameter, i.e. a big
166 * representation of the same number is required. Promoting the original
167 * argument comes with multiple problems, such as modifying a read-only
168 * argument, the responsibility of deallocation and the execution cost. Instead,
169 * we make a copy by 'faking' the IMath internal structure.
171 * We reserve the maximum number of required digits on the stack to avoid heap
174 * mp_digit can be uint32_t or uint16_t. This code must work for little and big
175 * endian digits. The structure for an uint64_t argument and 32-bit mp_digits is
178 * |----------------------------|
181 * |-------------||-------------|
183 * digits[1] digits[0]
184 * Most sig digit Least sig digit
188 mp_digit digits
[(sizeof(uintmax_t) + sizeof(mp_digit
) - 1) /
190 } isl_sioimath_scratchspace_t
;
192 /* Convert a native integer to IMath's digit representation. A native integer
193 * might be big- or little endian, but IMath always stores the least significant
194 * digit in the lowest array indices. memcpy therefore is not possible.
196 * We also have to consider that long and mp_digit can be of different sizes,
197 * depending on the compiler (LP64, LLP64) and IMath's USE_64BIT_WORDS. This
198 * macro should work for all of them.
200 * "used" is set to the number of written digits. It must be minimal (IMath
201 * checks zeroness using the used field), but always at least one. Also note
202 * that the result of num>>(sizeof(num)*CHAR_BIT) is undefined.
204 #define ISL_SIOIMATH_TO_DIGITS(num, digits, used) \
209 ((num) >> (sizeof(mp_digit) * CHAR_BIT * i)); \
211 if (i >= (sizeof(num) + sizeof(mp_digit) - 1) / \
214 if (((num) >> (sizeof(mp_digit) * CHAR_BIT * i)) == 0) \
220 inline void isl_siomath_uint32_to_digits(uint32_t num
, mp_digit
*digits
,
223 ISL_SIOIMATH_TO_DIGITS(num
, digits
, *used
);
226 inline void isl_siomath_ulong_to_digits(unsigned long num
, mp_digit
*digits
,
229 ISL_SIOIMATH_TO_DIGITS(num
, digits
, *used
);
232 inline void isl_siomath_uint64_to_digits(uint64_t num
, mp_digit
*digits
,
235 ISL_SIOIMATH_TO_DIGITS(num
, digits
, *used
);
238 /* Get the IMath representation of an isl_int without modifying it.
239 * For the case it is not in big representation yet, pass some scratch space we
240 * can use to store the big representation in.
241 * In order to avoid requiring init and free on the scratch space, we directly
242 * modify the internal representation.
244 * The name derives from its indented use: getting the big representation of an
245 * input (src) argument.
247 inline mp_int
isl_sioimath_bigarg_src(isl_sioimath arg
,
248 isl_sioimath_scratchspace_t
*scratch
)
254 if (isl_sioimath_decode_big(arg
, &big
))
257 small
= isl_sioimath_get_small(arg
);
258 scratch
->big
.digits
= scratch
->digits
;
259 scratch
->big
.alloc
= ARRAY_SIZE(scratch
->digits
);
261 scratch
->big
.sign
= MP_ZPOS
;
264 scratch
->big
.sign
= MP_NEG
;
268 isl_siomath_uint32_to_digits(num
, scratch
->digits
, &scratch
->big
.used
);
269 return &scratch
->big
;
272 /* Create a temporary IMath mp_int for a signed long.
274 inline mp_int
isl_sioimath_siarg_src(signed long arg
,
275 isl_sioimath_scratchspace_t
*scratch
)
279 scratch
->big
.digits
= scratch
->digits
;
280 scratch
->big
.alloc
= ARRAY_SIZE(scratch
->digits
);
282 scratch
->big
.sign
= MP_ZPOS
;
285 scratch
->big
.sign
= MP_NEG
;
286 num
= (arg
== LONG_MIN
) ? ((unsigned long) LONG_MAX
) + 1 : -arg
;
289 isl_siomath_ulong_to_digits(num
, scratch
->digits
, &scratch
->big
.used
);
290 return &scratch
->big
;
293 /* Create a temporary IMath mp_int for an int64_t.
295 inline mp_int
isl_sioimath_si64arg_src(int64_t arg
,
296 isl_sioimath_scratchspace_t
*scratch
)
300 scratch
->big
.digits
= scratch
->digits
;
301 scratch
->big
.alloc
= ARRAY_SIZE(scratch
->digits
);
303 scratch
->big
.sign
= MP_ZPOS
;
306 scratch
->big
.sign
= MP_NEG
;
307 num
= (arg
== INT64_MIN
) ? ((uint64_t) INT64_MAX
) + 1 : -arg
;
310 isl_siomath_uint64_to_digits(num
, scratch
->digits
, &scratch
->big
.used
);
311 return &scratch
->big
;
314 /* Create a temporary IMath mp_int for an unsigned long.
316 inline mp_int
isl_sioimath_uiarg_src(unsigned long arg
,
317 isl_sioimath_scratchspace_t
*scratch
)
319 scratch
->big
.digits
= scratch
->digits
;
320 scratch
->big
.alloc
= ARRAY_SIZE(scratch
->digits
);
321 scratch
->big
.sign
= MP_ZPOS
;
323 isl_siomath_ulong_to_digits(arg
, scratch
->digits
, &scratch
->big
.used
);
324 return &scratch
->big
;
327 /* Ensure big representation. Does not preserve the current number.
328 * Callers may use the fact that the value _is_ preserved if the presentation
331 inline mp_int
isl_sioimath_reinit_big(isl_sioimath_ptr ptr
)
333 if (isl_sioimath_is_small(*ptr
))
334 *ptr
= isl_sioimath_encode_big(mp_int_alloc());
335 return isl_sioimath_get_big(*ptr
);
338 /* Set ptr to a number in small representation.
340 inline void isl_sioimath_set_small(isl_sioimath_ptr ptr
, int32_t val
)
342 if (isl_sioimath_is_big(*ptr
))
343 mp_int_free(isl_sioimath_get_big(*ptr
));
344 *ptr
= isl_sioimath_encode_small(val
);
347 /* Set ptr to val, choosing small representation if possible.
349 inline void isl_sioimath_set_int32(isl_sioimath_ptr ptr
, int32_t val
)
351 if (ISL_SIOIMATH_SMALL_MIN
<= val
&& val
<= ISL_SIOIMATH_SMALL_MAX
) {
352 isl_sioimath_set_small(ptr
, val
);
356 mp_int_init_value(isl_sioimath_reinit_big(ptr
), val
);
359 /* Assign an int64_t number using small representation if possible.
361 inline void isl_sioimath_set_int64(isl_sioimath_ptr ptr
, int64_t val
)
363 if (ISL_SIOIMATH_SMALL_MIN
<= val
&& val
<= ISL_SIOIMATH_SMALL_MAX
) {
364 isl_sioimath_set_small(ptr
, val
);
368 isl_sioimath_scratchspace_t scratch
;
369 mp_int_copy(isl_sioimath_si64arg_src(val
, &scratch
),
370 isl_sioimath_reinit_big(ptr
));
373 /* Convert to big representation while preserving the current number.
375 inline void isl_sioimath_promote(isl_sioimath_ptr dst
)
379 if (isl_sioimath_is_big(*dst
))
382 small
= isl_sioimath_get_small(*dst
);
383 mp_int_set_value(isl_sioimath_reinit_big(dst
), small
);
386 /* Convert to small representation while preserving the current number. Does
387 * nothing if dst doesn't fit small representation.
389 inline void isl_sioimath_try_demote(isl_sioimath_ptr dst
)
393 if (isl_sioimath_is_small(*dst
))
396 if (mp_int_to_int(isl_sioimath_get_big(*dst
), &small
) != MP_OK
)
399 if (ISL_SIOIMATH_SMALL_MIN
<= small
&& small
<= ISL_SIOIMATH_SMALL_MAX
)
400 isl_sioimath_set_small(dst
, small
);
403 /* Initialize an isl_int. The implicit value is 0 in small representation.
405 inline void isl_sioimath_init(isl_sioimath_ptr dst
)
407 *dst
= isl_sioimath_encode_small(0);
410 /* Free the resources taken by an isl_int.
412 inline void isl_sioimath_clear(isl_sioimath_ptr dst
)
414 if (isl_sioimath_is_small(*dst
))
417 mp_int_free(isl_sioimath_get_big(*dst
));
420 /* Copy the value of one isl_int to another.
422 inline void isl_sioimath_set(isl_sioimath_ptr dst
, isl_sioimath_src val
)
424 if (isl_sioimath_is_small(val
)) {
425 isl_sioimath_set_small(dst
, isl_sioimath_get_small(val
));
429 mp_int_copy(isl_sioimath_get_big(val
), isl_sioimath_reinit_big(dst
));
432 /* Store a signed long into an isl_int.
434 inline void isl_sioimath_set_si(isl_sioimath_ptr dst
, long val
)
436 if (ISL_SIOIMATH_SMALL_MIN
<= val
&& val
<= ISL_SIOIMATH_SMALL_MAX
) {
437 isl_sioimath_set_small(dst
, val
);
441 mp_int_set_value(isl_sioimath_reinit_big(dst
), val
);
444 /* Store an unsigned long into an isl_int.
446 inline void isl_sioimath_set_ui(isl_sioimath_ptr dst
, unsigned long val
)
448 if (val
<= ISL_SIOIMATH_SMALL_MAX
) {
449 isl_sioimath_set_small(dst
, val
);
453 mp_int_set_uvalue(isl_sioimath_reinit_big(dst
), val
);
456 /* Return whether a number can be represented by a signed long.
458 inline int isl_sioimath_fits_slong(isl_sioimath_src val
)
462 if (isl_sioimath_is_small(val
))
465 return mp_int_to_int(isl_sioimath_get_big(val
), &dummy
) == MP_OK
;
468 /* Return a number as signed long. Result is undefined if the number cannot be
469 * represented as long.
471 inline long isl_sioimath_get_si(isl_sioimath_src val
)
475 if (isl_sioimath_is_small(val
))
476 return isl_sioimath_get_small(val
);
478 mp_int_to_int(isl_sioimath_get_big(val
), &result
);
482 /* Return whether a number can be represented as unsigned long.
484 inline int isl_sioimath_fits_ulong(isl_sioimath_src val
)
488 if (isl_sioimath_is_small(val
))
489 return isl_sioimath_get_small(val
) >= 0;
491 return mp_int_to_uint(isl_sioimath_get_big(val
), &dummy
) == MP_OK
;
494 /* Return a number as unsigned long. Result is undefined if the number cannot be
495 * represented as unsigned long.
497 inline unsigned long isl_sioimath_get_ui(isl_sioimath_src val
)
501 if (isl_sioimath_is_small(val
))
502 return isl_sioimath_get_small(val
);
504 mp_int_to_uint(isl_sioimath_get_big(val
), &result
);
508 /* Return a number as floating point value.
510 inline double isl_sioimath_get_d(isl_sioimath_src val
)
516 if (isl_sioimath_is_small(val
))
517 return isl_sioimath_get_small(val
);
519 big
= isl_sioimath_get_big(val
);
520 for (i
= 0; i
< big
->used
; ++i
)
521 result
= result
* (double) ((uintmax_t) MP_DIGIT_MAX
+ 1) +
522 (double) big
->digits
[i
];
524 if (big
->sign
== MP_NEG
)
530 /* Format a number as decimal string.
532 * The largest possible string from small representation is 12 characters
535 inline char *isl_sioimath_get_str(isl_sioimath_src val
)
539 if (isl_sioimath_is_small(val
)) {
541 snprintf(result
, 12, "%" PRIi32
, isl_sioimath_get_small(val
));
545 return impz_get_str(NULL
, 10, isl_sioimath_get_big(val
));
548 /* Return the absolute value.
550 inline void isl_sioimath_abs(isl_sioimath_ptr dst
, isl_sioimath_src arg
)
552 if (isl_sioimath_is_small(arg
)) {
553 isl_sioimath_set_small(dst
, labs(isl_sioimath_get_small(arg
)));
557 mp_int_abs(isl_sioimath_get_big(arg
), isl_sioimath_reinit_big(dst
));
560 /* Return the negation of a number.
562 inline void isl_sioimath_neg(isl_sioimath_ptr dst
, isl_sioimath_src arg
)
564 if (isl_sioimath_is_small(arg
)) {
565 isl_sioimath_set_small(dst
, -isl_sioimath_get_small(arg
));
569 mp_int_neg(isl_sioimath_get_big(arg
), isl_sioimath_reinit_big(dst
));
572 /* Swap two isl_ints.
574 * isl_sioimath can be copied bytewise; nothing depends on its address. It can
575 * also be stored in a CPU register.
577 inline void isl_sioimath_swap(isl_sioimath_ptr lhs
, isl_sioimath_ptr rhs
)
579 isl_sioimath tmp
= *lhs
;
584 /* Add an unsigned long to the number.
586 * On LP64 unsigned long exceeds the range of an int64_t, therefore we check in
587 * advance whether small representation possibly overflows.
589 inline void isl_sioimath_add_ui(isl_sioimath_ptr dst
, isl_sioimath lhs
,
593 isl_sioimath_scratchspace_t lhsscratch
;
595 if (isl_sioimath_decode_small(lhs
, &smalllhs
) &&
596 (rhs
<= (uint64_t) INT64_MAX
- (uint64_t) ISL_SIOIMATH_SMALL_MAX
)) {
597 isl_sioimath_set_int64(dst
, (int64_t) smalllhs
+ rhs
);
601 impz_add_ui(isl_sioimath_reinit_big(dst
),
602 isl_sioimath_bigarg_src(lhs
, &lhsscratch
), rhs
);
603 isl_sioimath_try_demote(dst
);
606 /* Subtract an unsigned long.
608 * On LP64 unsigned long exceeds the range of an int64_t. If
609 * ISL_SIOIMATH_SMALL_MIN-rhs>=INT64_MIN we can do the calculation using int64_t
610 * without risking an overflow.
612 inline void isl_sioimath_sub_ui(isl_sioimath_ptr dst
, isl_sioimath lhs
,
616 isl_sioimath_scratchspace_t lhsscratch
;
618 if (isl_sioimath_decode_small(lhs
, &smalllhs
) &&
619 (rhs
< (uint64_t) INT64_MIN
- (uint64_t) ISL_SIOIMATH_SMALL_MIN
)) {
620 isl_sioimath_set_int64(dst
, (int64_t) smalllhs
- rhs
);
624 impz_sub_ui(isl_sioimath_reinit_big(dst
),
625 isl_sioimath_bigarg_src(lhs
, &lhsscratch
), rhs
);
626 isl_sioimath_try_demote(dst
);
629 /* Sum of two isl_ints.
631 inline void isl_sioimath_add(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
632 isl_sioimath_src rhs
)
634 isl_sioimath_scratchspace_t scratchlhs
, scratchrhs
;
635 int32_t smalllhs
, smallrhs
;
637 if (isl_sioimath_decode_small(lhs
, &smalllhs
) &&
638 isl_sioimath_decode_small(rhs
, &smallrhs
)) {
639 isl_sioimath_set_int64(
640 dst
, (int64_t) smalllhs
+ (int64_t) smallrhs
);
644 mp_int_add(isl_sioimath_bigarg_src(lhs
, &scratchlhs
),
645 isl_sioimath_bigarg_src(rhs
, &scratchrhs
),
646 isl_sioimath_reinit_big(dst
));
647 isl_sioimath_try_demote(dst
);
650 /* Subtract two isl_ints.
652 inline void isl_sioimath_sub(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
653 isl_sioimath_src rhs
)
655 isl_sioimath_scratchspace_t scratchlhs
, scratchrhs
;
656 int32_t smalllhs
, smallrhs
;
658 if (isl_sioimath_decode_small(lhs
, &smalllhs
) &&
659 isl_sioimath_decode_small(rhs
, &smallrhs
)) {
660 isl_sioimath_set_int64(
661 dst
, (int64_t) smalllhs
- (int64_t) smallrhs
);
665 mp_int_sub(isl_sioimath_bigarg_src(lhs
, &scratchlhs
),
666 isl_sioimath_bigarg_src(rhs
, &scratchrhs
),
667 isl_sioimath_reinit_big(dst
));
668 isl_sioimath_try_demote(dst
);
671 /* Multiply two isl_ints.
673 inline void isl_sioimath_mul(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
674 isl_sioimath_src rhs
)
676 isl_sioimath_scratchspace_t scratchlhs
, scratchrhs
;
677 int32_t smalllhs
, smallrhs
;
679 if (isl_sioimath_decode_small(lhs
, &smalllhs
) &&
680 isl_sioimath_decode_small(rhs
, &smallrhs
)) {
681 isl_sioimath_set_int64(
682 dst
, (int64_t) smalllhs
* (int64_t) smallrhs
);
686 mp_int_mul(isl_sioimath_bigarg_src(lhs
, &scratchlhs
),
687 isl_sioimath_bigarg_src(rhs
, &scratchrhs
),
688 isl_sioimath_reinit_big(dst
));
689 isl_sioimath_try_demote(dst
);
692 /* Shift lhs by rhs bits to the left and store the result in dst. Effectively,
693 * this operation computes 'lhs * 2^rhs'.
695 inline void isl_sioimath_mul_2exp(isl_sioimath_ptr dst
, isl_sioimath lhs
,
698 isl_sioimath_scratchspace_t scratchlhs
;
701 if (isl_sioimath_decode_small(lhs
, &smalllhs
) && (rhs
<= 32ul)) {
702 isl_sioimath_set_int64(dst
, ((int64_t) smalllhs
) << rhs
);
706 mp_int_mul_pow2(isl_sioimath_bigarg_src(lhs
, &scratchlhs
), rhs
,
707 isl_sioimath_reinit_big(dst
));
710 /* Multiply an isl_int and a signed long.
712 inline void isl_sioimath_mul_si(isl_sioimath_ptr dst
, isl_sioimath lhs
,
715 isl_sioimath_scratchspace_t scratchlhs
, scratchrhs
;
718 if (isl_sioimath_decode_small(lhs
, &smalllhs
) && (rhs
> LONG_MIN
) &&
719 (labs(rhs
) <= UINT32_MAX
)) {
720 isl_sioimath_set_int64(dst
, (int64_t) smalllhs
* (int64_t) rhs
);
724 mp_int_mul(isl_sioimath_bigarg_src(lhs
, &scratchlhs
),
725 isl_sioimath_siarg_src(rhs
, &scratchrhs
),
726 isl_sioimath_reinit_big(dst
));
727 isl_sioimath_try_demote(dst
);
730 /* Multiply an isl_int and an unsigned long.
732 inline void isl_sioimath_mul_ui(isl_sioimath_ptr dst
, isl_sioimath lhs
,
735 isl_sioimath_scratchspace_t scratchlhs
, scratchrhs
;
738 if (isl_sioimath_decode_small(lhs
, &smalllhs
) && (rhs
<= UINT32_MAX
)) {
739 isl_sioimath_set_int64(dst
, (int64_t) smalllhs
* (int64_t) rhs
);
743 mp_int_mul(isl_sioimath_bigarg_src(lhs
, &scratchlhs
),
744 isl_sioimath_uiarg_src(rhs
, &scratchrhs
),
745 isl_sioimath_reinit_big(dst
));
746 isl_sioimath_try_demote(dst
);
749 /* Compute the power of an isl_int to an unsigned long.
750 * Always let IMath do it; the result is unlikely to be small except in some
754 inline void isl_sioimath_pow_ui(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
757 isl_sioimath_scratchspace_t scratchlhs
, scratchrhs
;
762 isl_sioimath_set_small(dst
, 1);
765 isl_sioimath_set(dst
, lhs
);
768 isl_sioimath_mul(dst
, lhs
, lhs
);
772 if (isl_sioimath_decode_small(lhs
, &smalllhs
)) {
775 isl_sioimath_set_small(dst
, 0);
778 isl_sioimath_set_small(dst
, 1);
781 isl_sioimath_set_small(dst
, 1);
782 isl_sioimath_mul_2exp(dst
, *dst
, rhs
);
785 if ((MP_SMALL_MIN
<= rhs
) && (rhs
<= MP_SMALL_MAX
)) {
786 mp_int_expt_value(smalllhs
, rhs
,
787 isl_sioimath_reinit_big(dst
));
788 isl_sioimath_try_demote(dst
);
794 mp_int_expt_full(isl_sioimath_bigarg_src(lhs
, &scratchlhs
),
795 isl_sioimath_uiarg_src(rhs
, &scratchrhs
),
796 isl_sioimath_reinit_big(dst
));
797 isl_sioimath_try_demote(dst
);
800 /* Fused multiply-add.
802 inline void isl_sioimath_addmul(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
803 isl_sioimath_src rhs
)
806 isl_sioimath_init(&tmp
);
807 isl_sioimath_mul(&tmp
, lhs
, rhs
);
808 isl_sioimath_add(dst
, *dst
, tmp
);
809 isl_sioimath_clear(&tmp
);
812 /* Fused multiply-add with an unsigned long.
814 inline void isl_sioimath_addmul_ui(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
818 isl_sioimath_init(&tmp
);
819 isl_sioimath_mul_ui(&tmp
, lhs
, rhs
);
820 isl_sioimath_add(dst
, *dst
, tmp
);
821 isl_sioimath_clear(&tmp
);
824 /* Fused multiply-subtract.
826 inline void isl_sioimath_submul(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
827 isl_sioimath_src rhs
)
830 isl_sioimath_init(&tmp
);
831 isl_sioimath_mul(&tmp
, lhs
, rhs
);
832 isl_sioimath_sub(dst
, *dst
, tmp
);
833 isl_sioimath_clear(&tmp
);
836 /* Fused multiply-add with an unsigned long.
838 inline void isl_sioimath_submul_ui(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
842 isl_sioimath_init(&tmp
);
843 isl_sioimath_mul_ui(&tmp
, lhs
, rhs
);
844 isl_sioimath_sub(dst
, *dst
, tmp
);
845 isl_sioimath_clear(&tmp
);
848 void isl_sioimath_gcd(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
849 isl_sioimath_src rhs
);
850 void isl_sioimath_lcm(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
851 isl_sioimath_src rhs
);
853 /* Divide lhs by rhs, rounding to zero (Truncate).
855 inline void isl_sioimath_tdiv_q(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
856 isl_sioimath_src rhs
)
858 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
859 int32_t lhssmall
, rhssmall
;
861 if (isl_sioimath_decode_small(lhs
, &lhssmall
) &&
862 isl_sioimath_decode_small(rhs
, &rhssmall
)) {
863 isl_sioimath_set_small(dst
, lhssmall
/ rhssmall
);
867 mp_int_div(isl_sioimath_bigarg_src(lhs
, &lhsscratch
),
868 isl_sioimath_bigarg_src(rhs
, &rhsscratch
),
869 isl_sioimath_reinit_big(dst
), NULL
);
870 isl_sioimath_try_demote(dst
);
874 /* Divide lhs by an unsigned long rhs, rounding to zero (Truncate).
876 inline void isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
879 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
882 if (isl_sioimath_is_small(lhs
) && (rhs
<= (unsigned long) INT32_MAX
)) {
883 lhssmall
= isl_sioimath_get_small(lhs
);
884 isl_sioimath_set_small(dst
, lhssmall
/ (int32_t) rhs
);
888 if (rhs
<= MP_SMALL_MAX
) {
889 mp_int_div_value(isl_sioimath_bigarg_src(lhs
, &lhsscratch
), rhs
,
890 isl_sioimath_reinit_big(dst
), NULL
);
891 isl_sioimath_try_demote(dst
);
895 mp_int_div(isl_sioimath_bigarg_src(lhs
, &lhsscratch
),
896 isl_sioimath_uiarg_src(rhs
, &rhsscratch
),
897 isl_sioimath_reinit_big(dst
), NULL
);
898 isl_sioimath_try_demote(dst
);
901 /* Divide lhs by rhs, rounding to positive infinity (Ceil).
903 inline void isl_sioimath_cdiv_q(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
904 isl_sioimath_src rhs
)
906 int32_t lhssmall
, rhssmall
;
907 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
910 if (isl_sioimath_decode_small(lhs
, &lhssmall
) &&
911 isl_sioimath_decode_small(rhs
, &rhssmall
)) {
912 if ((lhssmall
>= 0) && (rhssmall
>= 0))
913 q
= ((int64_t) lhssmall
+ (int64_t) rhssmall
- 1) /
915 else if ((lhssmall
< 0) && (rhssmall
< 0))
916 q
= ((int64_t) lhssmall
+ (int64_t) rhssmall
+ 1) /
919 q
= lhssmall
/ rhssmall
;
920 isl_sioimath_set_small(dst
, q
);
924 impz_cdiv_q(isl_sioimath_reinit_big(dst
),
925 isl_sioimath_bigarg_src(lhs
, &lhsscratch
),
926 isl_sioimath_bigarg_src(rhs
, &rhsscratch
));
927 isl_sioimath_try_demote(dst
);
930 /* Divide lhs by rhs, rounding to negative infinity (Floor).
932 inline void isl_sioimath_fdiv_q(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
933 isl_sioimath_src rhs
)
935 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
936 int32_t lhssmall
, rhssmall
;
939 if (isl_sioimath_decode_small(lhs
, &lhssmall
) &&
940 isl_sioimath_decode_small(rhs
, &rhssmall
)) {
941 if ((lhssmall
< 0) && (rhssmall
>= 0))
942 q
= ((int64_t) lhssmall
- ((int64_t) rhssmall
- 1)) /
944 else if ((lhssmall
>= 0) && (rhssmall
< 0))
945 q
= ((int64_t) lhssmall
- ((int64_t) rhssmall
+ 1)) /
948 q
= lhssmall
/ rhssmall
;
949 isl_sioimath_set_small(dst
, q
);
953 impz_fdiv_q(isl_sioimath_reinit_big(dst
),
954 isl_sioimath_bigarg_src(lhs
, &lhsscratch
),
955 isl_sioimath_bigarg_src(rhs
, &rhsscratch
));
956 isl_sioimath_try_demote(dst
);
959 /* Compute the division of lhs by a rhs of type unsigned long, rounding towards
960 * negative infinity (Floor).
962 inline void isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
965 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
968 if (isl_sioimath_decode_small(lhs
, &lhssmall
) && (rhs
<= INT32_MAX
)) {
970 q
= (uint32_t) lhssmall
/ rhs
;
972 q
= ((int64_t) lhssmall
- ((int64_t) rhs
- 1)) /
974 isl_sioimath_set_small(dst
, q
);
978 impz_fdiv_q(isl_sioimath_reinit_big(dst
),
979 isl_sioimath_bigarg_src(lhs
, &lhsscratch
),
980 isl_sioimath_uiarg_src(rhs
, &rhsscratch
));
981 isl_sioimath_try_demote(dst
);
984 /* Get the remainder of: lhs divided by rhs rounded towards negative infinite
987 inline void isl_sioimath_fdiv_r(isl_sioimath_ptr dst
, isl_sioimath_src lhs
,
988 isl_sioimath_src rhs
)
990 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
991 int64_t lhssmall
, rhssmall
;
994 if (isl_sioimath_is_small(lhs
) && isl_sioimath_is_small(rhs
)) {
995 lhssmall
= isl_sioimath_get_small(lhs
);
996 rhssmall
= isl_sioimath_get_small(rhs
);
997 r
= (rhssmall
+ lhssmall
% rhssmall
) % rhssmall
;
998 isl_sioimath_set_small(dst
, r
);
1002 impz_fdiv_r(isl_sioimath_reinit_big(dst
),
1003 isl_sioimath_bigarg_src(lhs
, &lhsscratch
),
1004 isl_sioimath_bigarg_src(rhs
, &rhsscratch
));
1005 isl_sioimath_try_demote(dst
);
1008 void isl_sioimath_read(isl_sioimath_ptr dst
, const char *str
);
1011 * +1 for a positive number
1012 * -1 for a negative number
1013 * 0 if the number is zero
1015 inline int isl_sioimath_sgn(isl_sioimath_src arg
)
1019 if (isl_sioimath_decode_small(arg
, &small
))
1020 return (small
> 0) - (small
< 0);
1022 return mp_int_compare_zero(isl_sioimath_get_big(arg
));
1030 inline int isl_sioimath_cmp(isl_sioimath_src lhs
, isl_sioimath_src rhs
)
1032 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
1033 int32_t lhssmall
, rhssmall
;
1035 if (isl_sioimath_decode_small(lhs
, &lhssmall
) &&
1036 isl_sioimath_decode_small(rhs
, &rhssmall
))
1037 return (lhssmall
> rhssmall
) - (lhssmall
< rhssmall
);
1039 if (isl_sioimath_decode_small(rhs
, &rhssmall
))
1040 return mp_int_compare_value(
1041 isl_sioimath_bigarg_src(lhs
, &lhsscratch
), rhssmall
);
1043 if (isl_sioimath_decode_small(lhs
, &lhssmall
))
1044 return -mp_int_compare_value(
1045 isl_sioimath_bigarg_src(rhs
, &rhsscratch
), lhssmall
);
1047 return mp_int_compare(
1048 isl_sioimath_get_big(lhs
), isl_sioimath_get_big(rhs
));
1051 /* As isl_sioimath_cmp, but with signed long rhs.
1053 inline int isl_sioimath_cmp_si(isl_sioimath_src lhs
, signed long rhs
)
1057 if (isl_sioimath_decode_small(lhs
, &lhssmall
))
1058 return (lhssmall
> rhs
) - (lhssmall
< rhs
);
1060 return mp_int_compare_value(isl_sioimath_get_big(lhs
), rhs
);
1064 * +1 if |lhs| > |rhs|
1065 * -1 if |lhs| < |rhs|
1066 * 0 if |lhs| = |rhs|
1068 inline int isl_sioimath_abs_cmp(isl_sioimath_src lhs
, isl_sioimath_src rhs
)
1070 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
1071 int32_t lhssmall
, rhssmall
;
1073 if (isl_sioimath_decode_small(lhs
, &lhssmall
) &&
1074 isl_sioimath_decode_small(rhs
, &rhssmall
)) {
1075 lhssmall
= labs(lhssmall
);
1076 rhssmall
= labs(rhssmall
);
1077 return (lhssmall
> rhssmall
) - (lhssmall
< rhssmall
);
1080 return mp_int_compare_unsigned(
1081 isl_sioimath_bigarg_src(lhs
, &lhsscratch
),
1082 isl_sioimath_bigarg_src(rhs
, &rhsscratch
));
1085 /* Return whether lhs is divisible by rhs.
1086 * In particular, can rhs be multiplied by some integer to result in lhs?
1087 * If rhs is zero, then this means lhs has to be zero too.
1089 inline int isl_sioimath_is_divisible_by(isl_sioimath_src lhs
,
1090 isl_sioimath_src rhs
)
1092 isl_sioimath_scratchspace_t lhsscratch
, rhsscratch
;
1093 int32_t lhssmall
, rhssmall
;
1097 if (isl_sioimath_sgn(rhs
) == 0)
1098 return isl_sioimath_sgn(lhs
) == 0;
1100 if (isl_sioimath_decode_small(lhs
, &lhssmall
) &&
1101 isl_sioimath_decode_small(rhs
, &rhssmall
))
1102 return lhssmall
% rhssmall
== 0;
1104 if (isl_sioimath_decode_small(rhs
, &rhssmall
))
1105 return mp_int_divisible_value(
1106 isl_sioimath_bigarg_src(lhs
, &lhsscratch
), rhssmall
);
1109 mp_int_div(isl_sioimath_bigarg_src(lhs
, &lhsscratch
),
1110 isl_sioimath_bigarg_src(rhs
, &rhsscratch
), NULL
, &rem
);
1111 cmp
= mp_int_compare_zero(&rem
);
1116 /* Return a hash code of an isl_sioimath.
1117 * The hash code for a number in small and big representation must be identical
1118 * on the same machine because small representation if not obligatory if fits.
1120 inline uint32_t isl_sioimath_hash(isl_sioimath_src arg
, uint32_t hash
)
1125 mp_digit digits
[(sizeof(uint32_t) + sizeof(mp_digit
) - 1) /
1128 const unsigned char *digitdata
= (const unsigned char *) &digits
;
1130 if (isl_sioimath_decode_small(arg
, &small
)) {
1132 isl_hash_byte(hash
, 0xFF);
1135 isl_siomath_uint32_to_digits(num
, digits
, &used
);
1136 for (i
= 0; i
< used
* sizeof(mp_digit
); i
+= 1)
1137 isl_hash_byte(hash
, digitdata
[i
]);
1141 return isl_imath_hash(isl_sioimath_get_big(arg
), hash
);
1144 /* Return the number of digits in a number of the given base or more, i.e. the
1145 * string length without sign and null terminator.
1147 * Current implementation for small representation returns the maximal number
1148 * of binary digits in that representation, which can be much larger than the
1149 * smallest possible solution.
1151 inline size_t isl_sioimath_sizeinbase(isl_sioimath_src arg
, int base
)
1155 if (isl_sioimath_decode_small(arg
, &small
))
1156 return sizeof(int32_t) * CHAR_BIT
- 1;
1158 return impz_sizeinbase(isl_sioimath_get_big(arg
), base
);
1161 void isl_sioimath_print(FILE *out
, isl_sioimath_src i
, int width
);
1162 void isl_sioimath_dump(isl_sioimath_src arg
);
1164 typedef isl_sioimath isl_int
[1];
1165 #define isl_int_init(i) isl_sioimath_init((i))
1166 #define isl_int_clear(i) isl_sioimath_clear((i))
1168 #define isl_int_set(r, i) isl_sioimath_set((r), *(i))
1169 #define isl_int_set_si(r, i) isl_sioimath_set_si((r), i)
1170 #define isl_int_set_ui(r, i) isl_sioimath_set_ui((r), i)
1171 #define isl_int_fits_slong(r) isl_sioimath_fits_slong(*(r))
1172 #define isl_int_get_si(r) isl_sioimath_get_si(*(r))
1173 #define isl_int_fits_ulong(r) isl_sioimath_fits_ulong(*(r))
1174 #define isl_int_get_ui(r) isl_sioimath_get_ui(*(r))
1175 #define isl_int_get_d(r) isl_sioimath_get_d(*(r))
1176 #define isl_int_get_str(r) isl_sioimath_get_str(*(r))
1177 #define isl_int_abs(r, i) isl_sioimath_abs((r), *(i))
1178 #define isl_int_neg(r, i) isl_sioimath_neg((r), *(i))
1179 #define isl_int_swap(i, j) isl_sioimath_swap((i), (j))
1180 #define isl_int_swap_or_set(i, j) isl_sioimath_swap((i), (j))
1181 #define isl_int_add_ui(r, i, j) isl_sioimath_add_ui((r), *(i), j)
1182 #define isl_int_sub_ui(r, i, j) isl_sioimath_sub_ui((r), *(i), j)
1184 #define isl_int_add(r, i, j) isl_sioimath_add((r), *(i), *(j))
1185 #define isl_int_sub(r, i, j) isl_sioimath_sub((r), *(i), *(j))
1186 #define isl_int_mul(r, i, j) isl_sioimath_mul((r), *(i), *(j))
1187 #define isl_int_mul_2exp(r, i, j) isl_sioimath_mul_2exp((r), *(i), j)
1188 #define isl_int_mul_si(r, i, j) isl_sioimath_mul_si((r), *(i), j)
1189 #define isl_int_mul_ui(r, i, j) isl_sioimath_mul_ui((r), *(i), j)
1190 #define isl_int_pow_ui(r, i, j) isl_sioimath_pow_ui((r), *(i), j)
1191 #define isl_int_addmul(r, i, j) isl_sioimath_addmul((r), *(i), *(j))
1192 #define isl_int_addmul_ui(r, i, j) isl_sioimath_addmul_ui((r), *(i), j)
1193 #define isl_int_submul(r, i, j) isl_sioimath_submul((r), *(i), *(j))
1194 #define isl_int_submul_ui(r, i, j) isl_sioimath_submul_ui((r), *(i), j)
1196 #define isl_int_gcd(r, i, j) isl_sioimath_gcd((r), *(i), *(j))
1197 #define isl_int_lcm(r, i, j) isl_sioimath_lcm((r), *(i), *(j))
1198 #define isl_int_divexact(r, i, j) isl_sioimath_tdiv_q((r), *(i), *(j))
1199 #define isl_int_divexact_ui(r, i, j) isl_sioimath_tdiv_q_ui((r), *(i), j)
1200 #define isl_int_tdiv_q(r, i, j) isl_sioimath_tdiv_q((r), *(i), *(j))
1201 #define isl_int_cdiv_q(r, i, j) isl_sioimath_cdiv_q((r), *(i), *(j))
1202 #define isl_int_fdiv_q(r, i, j) isl_sioimath_fdiv_q((r), *(i), *(j))
1203 #define isl_int_fdiv_r(r, i, j) isl_sioimath_fdiv_r((r), *(i), *(j))
1204 #define isl_int_fdiv_q_ui(r, i, j) isl_sioimath_fdiv_q_ui((r), *(i), j)
1206 #define isl_int_read(r, s) isl_sioimath_read((r), s)
1207 #define isl_int_sgn(i) isl_sioimath_sgn(*(i))
1208 #define isl_int_cmp(i, j) isl_sioimath_cmp(*(i), *(j))
1209 #define isl_int_cmp_si(i, si) isl_sioimath_cmp_si(*(i), si)
1210 #define isl_int_eq(i, j) (isl_sioimath_cmp(*(i), *(j)) == 0)
1211 #define isl_int_ne(i, j) (isl_sioimath_cmp(*(i), *(j)) != 0)
1212 #define isl_int_lt(i, j) (isl_sioimath_cmp(*(i), *(j)) < 0)
1213 #define isl_int_le(i, j) (isl_sioimath_cmp(*(i), *(j)) <= 0)
1214 #define isl_int_gt(i, j) (isl_sioimath_cmp(*(i), *(j)) > 0)
1215 #define isl_int_ge(i, j) (isl_sioimath_cmp(*(i), *(j)) >= 0)
1216 #define isl_int_abs_cmp(i, j) isl_sioimath_abs_cmp(*(i), *(j))
1217 #define isl_int_abs_eq(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) == 0)
1218 #define isl_int_abs_ne(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) != 0)
1219 #define isl_int_abs_lt(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) < 0)
1220 #define isl_int_abs_gt(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) > 0)
1221 #define isl_int_abs_ge(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) >= 0)
1222 #define isl_int_is_divisible_by(i, j) isl_sioimath_is_divisible_by(*(i), *(j))
1224 #define isl_int_hash(v, h) isl_sioimath_hash(*(v), h)
1225 #define isl_int_free_str(s) free(s)
1226 #define isl_int_print(out, i, width) isl_sioimath_print(out, *(i), width)
1228 #endif /* ISL_INT_SIOIMATH_H */