/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/isl_int_sioimath.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2015 INRIA Paris-Rocquencourt |
3 | | * |
4 | | * Use of this software is governed by the MIT license |
5 | | * |
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 |
12 | | |
13 | | #include <inttypes.h> |
14 | | #include <limits.h> |
15 | | #include <stdint.h> |
16 | | #include <stdlib.h> |
17 | | |
18 | | #include <isl_imath.h> |
19 | | #include <isl/hash.h> |
20 | | |
21 | 48.7M | #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array)) |
22 | | |
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. |
26 | | */ |
27 | | #if defined(_MSC_VER) && (_MSC_VER < 1900) |
28 | | #define inline __inline |
29 | | #endif |
30 | | |
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 |
36 | | * int32_t. |
37 | | * |
38 | | * Structure on 64 bit machines, with 8-byte aligment (3 bits): |
39 | | * |
40 | | * Big representation: |
41 | | * MSB LSB |
42 | | * |------------------------------------------------------------000 |
43 | | * | mpz_t* | |
44 | | * | != NULL | |
45 | | * |
46 | | * Small representation: |
47 | | * MSB 32 LSB |
48 | | * |------------------------------|00000000000000000000000000000001 |
49 | | * | int32_t | |
50 | | * | 2147483647 ... -2147483647 | |
51 | | * ^ |
52 | | * | |
53 | | * discriminator bit |
54 | | * |
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. |
61 | | * |
62 | | * We use native integer types and avoid union structures to avoid assumptions |
63 | | * on the machine's endianness. |
64 | | * |
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 |
70 | | * bit is zero) |
71 | | */ |
72 | | #if UINT64_MAX > UINTPTR_MAX |
73 | | typedef uint64_t isl_sioimath; |
74 | | #else |
75 | | typedef uintptr_t isl_sioimath; |
76 | | #endif |
77 | | |
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. |
81 | | * The operations are: |
82 | | * abs(INT32_MIN) |
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 |
87 | | * representation. |
88 | | */ |
89 | 1.79G | #define ISL_SIOIMATH_SMALL_MIN (-INT32_MAX) |
90 | | |
91 | | /* Largest possible number in small representation */ |
92 | 1.78G | #define ISL_SIOIMATH_SMALL_MAX INT32_MAX |
93 | | |
94 | | /* Used for function parameters the function modifies. */ |
95 | | typedef isl_sioimath *isl_sioimath_ptr; |
96 | | |
97 | | /* Used for function parameters that are read-only. */ |
98 | | typedef isl_sioimath isl_sioimath_src; |
99 | | |
100 | | /* Return whether the argument is stored in small representation. |
101 | | */ |
102 | | inline int isl_sioimath_is_small(isl_sioimath val) |
103 | 11.9G | { |
104 | 11.9G | return val & 0x00000001; |
105 | 11.9G | } |
106 | | |
107 | | /* Return whether the argument is stored in big representation. |
108 | | */ |
109 | | inline int isl_sioimath_is_big(isl_sioimath val) |
110 | 3.35G | { |
111 | 3.35G | return !isl_sioimath_is_small(val); |
112 | 3.35G | } |
113 | | |
114 | | /* Get the number of an isl_int in small representation. Result is undefined if |
115 | | * val is not stored in that format. |
116 | | */ |
117 | | inline int32_t isl_sioimath_get_small(isl_sioimath val) |
118 | 7.78G | { |
119 | 7.78G | return val >> 32; |
120 | 7.78G | } |
121 | | |
122 | | /* Get the number of an in isl_int in big representation. Result is undefined if |
123 | | * val is not stored in that format. |
124 | | */ |
125 | | inline mp_int isl_sioimath_get_big(isl_sioimath val) |
126 | 288M | { |
127 | 288M | return (mp_int)(uintptr_t) val; |
128 | 288M | } |
129 | | |
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. |
135 | | */ |
136 | | inline int isl_sioimath_decode_small(isl_sioimath val, int32_t *small) |
137 | 6.40G | { |
138 | 6.40G | *small = isl_sioimath_get_small(val); |
139 | 6.40G | return isl_sioimath_is_small(val); |
140 | 6.40G | } |
141 | | |
142 | | /* Return 1 if val is stored in big representation and store its value to big. |
143 | | */ |
144 | | inline int isl_sioimath_decode_big(isl_sioimath val, mp_int *big) |
145 | 110M | { |
146 | 110M | *big = isl_sioimath_get_big(val); |
147 | 110M | return isl_sioimath_is_big(val); |
148 | 110M | } |
149 | | |
150 | | /* Encode a small representation into an isl_int. |
151 | | */ |
152 | | inline isl_sioimath isl_sioimath_encode_small(int32_t val) |
153 | 3.97G | { |
154 | 3.97G | return ((isl_sioimath) val) << 32 | 0x00000001; |
155 | 3.97G | } |
156 | | |
157 | | /* Encode a big representation. |
158 | | */ |
159 | | inline isl_sioimath isl_sioimath_encode_big(mp_int val) |
160 | 37.0M | { |
161 | 37.0M | return (isl_sioimath)(uintptr_t) val; |
162 | 37.0M | } |
163 | | |
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. |
170 | | * |
171 | | * We reserve the maximum number of required digits on the stack to avoid heap |
172 | | * allocations. |
173 | | * |
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 |
176 | | * sketched below. |
177 | | * |
178 | | * |----------------------------| |
179 | | * uint64_t |
180 | | * |
181 | | * |-------------||-------------| |
182 | | * mp_digit mp_digit |
183 | | * digits[1] digits[0] |
184 | | * Most sig digit Least sig digit |
185 | | */ |
186 | | typedef struct { |
187 | | mpz_t big; |
188 | | mp_digit digits[(sizeof(uintmax_t) + sizeof(mp_digit) - 1) / |
189 | | sizeof(mp_digit)]; |
190 | | } isl_sioimath_scratchspace_t; |
191 | | |
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. |
195 | | * |
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. |
199 | | * |
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. |
203 | | */ |
204 | | #define ISL_SIOIMATH_TO_DIGITS(num, digits, used) \ |
205 | 100M | do { \ |
206 | 100M | int i = 0; \ |
207 | 102M | do { \ |
208 | 102M | (digits)[i] = \ |
209 | 102M | ((num) >> (sizeof(mp_digit) * CHAR_BIT * i)); \ |
210 | 102M | i += 1; \ |
211 | 102M | if (i >= (sizeof(num) + sizeof(mp_digit) - 1) / \ |
212 | 102M | sizeof(mp_digit)) \ |
213 | 102M | break100M ; \ |
214 | 102M | if (2.23M ((num) >> (sizeof(mp_digit) * CHAR_BIT * i)) == 02.23M ) \ |
215 | 2.23M | break248k ; \ |
216 | 2.23M | } while (11.98M ); \ |
217 | 100M | (used) = i; \ |
218 | 100M | } while (0) |
219 | | |
220 | | inline void isl_siomath_uint32_to_digits(uint32_t num, mp_digit *digits, |
221 | | mp_size *used) |
222 | 98.1M | { |
223 | 98.1M | ISL_SIOIMATH_TO_DIGITS(num, digits, *used); |
224 | 98.1M | } |
225 | | |
226 | | inline void isl_siomath_ulong_to_digits(unsigned long num, mp_digit *digits, |
227 | | mp_size *used) |
228 | 22.7k | { |
229 | 22.7k | ISL_SIOIMATH_TO_DIGITS(num, digits, *used); |
230 | 22.7k | } |
231 | | |
232 | | inline void isl_siomath_uint64_to_digits(uint64_t num, mp_digit *digits, |
233 | | mp_size *used) |
234 | 2.20M | { |
235 | 2.20M | ISL_SIOIMATH_TO_DIGITS(num, digits, *used); |
236 | 2.20M | } |
237 | | |
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. |
243 | | * |
244 | | * The name derives from its indented use: getting the big representation of an |
245 | | * input (src) argument. |
246 | | */ |
247 | | inline mp_int isl_sioimath_bigarg_src(isl_sioimath arg, |
248 | | isl_sioimath_scratchspace_t *scratch) |
249 | 110M | { |
250 | 110M | mp_int big; |
251 | 110M | int32_t small; |
252 | 110M | uint32_t num; |
253 | 110M | |
254 | 110M | if (isl_sioimath_decode_big(arg, &big)) |
255 | 63.9M | return big; |
256 | 46.5M | |
257 | 46.5M | small = isl_sioimath_get_small(arg); |
258 | 46.5M | scratch->big.digits = scratch->digits; |
259 | 46.5M | scratch->big.alloc = ARRAY_SIZE(scratch->digits); |
260 | 46.5M | if (small >= 0) { |
261 | 43.7M | scratch->big.sign = MP_ZPOS; |
262 | 43.7M | num = small; |
263 | 43.7M | } else { |
264 | 2.72M | scratch->big.sign = MP_NEG; |
265 | 2.72M | num = -small; |
266 | 2.72M | } |
267 | 46.5M | |
268 | 46.5M | isl_siomath_uint32_to_digits(num, scratch->digits, &scratch->big.used); |
269 | 46.5M | return &scratch->big; |
270 | 46.5M | } |
271 | | |
272 | | /* Create a temporary IMath mp_int for a signed long. |
273 | | */ |
274 | | inline mp_int isl_sioimath_siarg_src(signed long arg, |
275 | | isl_sioimath_scratchspace_t *scratch) |
276 | 0 | { |
277 | 0 | unsigned long num; |
278 | 0 |
|
279 | 0 | scratch->big.digits = scratch->digits; |
280 | 0 | scratch->big.alloc = ARRAY_SIZE(scratch->digits); |
281 | 0 | if (arg >= 0) { |
282 | 0 | scratch->big.sign = MP_ZPOS; |
283 | 0 | num = arg; |
284 | 0 | } else { |
285 | 0 | scratch->big.sign = MP_NEG; |
286 | 0 | num = (arg == LONG_MIN) ? ((unsigned long) LONG_MAX) + 1 : -arg; |
287 | 0 | } |
288 | 0 |
|
289 | 0 | isl_siomath_ulong_to_digits(num, scratch->digits, &scratch->big.used); |
290 | 0 | return &scratch->big; |
291 | 0 | } |
292 | | |
293 | | /* Create a temporary IMath mp_int for an int64_t. |
294 | | */ |
295 | | inline mp_int isl_sioimath_si64arg_src(int64_t arg, |
296 | | isl_sioimath_scratchspace_t *scratch) |
297 | 2.20M | { |
298 | 2.20M | uint64_t num; |
299 | 2.20M | |
300 | 2.20M | scratch->big.digits = scratch->digits; |
301 | 2.20M | scratch->big.alloc = ARRAY_SIZE(scratch->digits); |
302 | 2.20M | if (arg >= 0) { |
303 | 1.29M | scratch->big.sign = MP_ZPOS; |
304 | 1.29M | num = arg; |
305 | 1.29M | } else { |
306 | 916k | scratch->big.sign = MP_NEG; |
307 | 916k | num = (arg == INT64_MIN) ? ((uint64_t) INT64_MAX) + 10 : -arg; |
308 | 916k | } |
309 | 2.20M | |
310 | 2.20M | isl_siomath_uint64_to_digits(num, scratch->digits, &scratch->big.used); |
311 | 2.20M | return &scratch->big; |
312 | 2.20M | } |
313 | | |
314 | | /* Create a temporary IMath mp_int for an unsigned long. |
315 | | */ |
316 | | inline mp_int isl_sioimath_uiarg_src(unsigned long arg, |
317 | | isl_sioimath_scratchspace_t *scratch) |
318 | 22.7k | { |
319 | 22.7k | scratch->big.digits = scratch->digits; |
320 | 22.7k | scratch->big.alloc = ARRAY_SIZE(scratch->digits); |
321 | 22.7k | scratch->big.sign = MP_ZPOS; |
322 | 22.7k | |
323 | 22.7k | isl_siomath_ulong_to_digits(arg, scratch->digits, &scratch->big.used); |
324 | 22.7k | return &scratch->big; |
325 | 22.7k | } |
326 | | |
327 | | /* Ensure big representation. Does not preserve the current number. |
328 | | * Callers may use the fact that the value _is_ preserved if the presentation |
329 | | * was big before. |
330 | | */ |
331 | | inline mp_int isl_sioimath_reinit_big(isl_sioimath_ptr ptr) |
332 | 62.7M | { |
333 | 62.7M | if (isl_sioimath_is_small(*ptr)) |
334 | 36.6M | *ptr = isl_sioimath_encode_big(mp_int_alloc()); |
335 | 62.7M | return isl_sioimath_get_big(*ptr); |
336 | 62.7M | } |
337 | | |
338 | | /* Set ptr to a number in small representation. |
339 | | */ |
340 | | inline void isl_sioimath_set_small(isl_sioimath_ptr ptr, int32_t val) |
341 | 3.24G | { |
342 | 3.24G | if (isl_sioimath_is_big(*ptr)) |
343 | 29.9M | mp_int_free(isl_sioimath_get_big(*ptr)); |
344 | 3.24G | *ptr = isl_sioimath_encode_small(val); |
345 | 3.24G | } |
346 | | |
347 | | /* Set ptr to val, choosing small representation if possible. |
348 | | */ |
349 | | inline void isl_sioimath_set_int32(isl_sioimath_ptr ptr, int32_t val) |
350 | 0 | { |
351 | 0 | if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) { |
352 | 0 | isl_sioimath_set_small(ptr, val); |
353 | 0 | return; |
354 | 0 | } |
355 | 0 | |
356 | 0 | mp_int_init_value(isl_sioimath_reinit_big(ptr), val); |
357 | 0 | } |
358 | | |
359 | | /* Assign an int64_t number using small representation if possible. |
360 | | */ |
361 | | inline void isl_sioimath_set_int64(isl_sioimath_ptr ptr, int64_t val) |
362 | 1.44G | { |
363 | 1.44G | if (ISL_SIOIMATH_SMALL_MIN <= val && val <= 1.44G ISL_SIOIMATH_SMALL_MAX1.44G ) { |
364 | 1.43G | isl_sioimath_set_small(ptr, val); |
365 | 1.43G | return; |
366 | 1.43G | } |
367 | 2.20M | |
368 | 2.20M | isl_sioimath_scratchspace_t scratch; |
369 | 2.20M | mp_int_copy(isl_sioimath_si64arg_src(val, &scratch), |
370 | 2.20M | isl_sioimath_reinit_big(ptr)); |
371 | 2.20M | } |
372 | | |
373 | | /* Convert to big representation while preserving the current number. |
374 | | */ |
375 | | inline void isl_sioimath_promote(isl_sioimath_ptr dst) |
376 | 0 | { |
377 | 0 | int32_t small; |
378 | 0 |
|
379 | 0 | if (isl_sioimath_is_big(*dst)) |
380 | 0 | return; |
381 | 0 | |
382 | 0 | small = isl_sioimath_get_small(*dst); |
383 | 0 | mp_int_set_value(isl_sioimath_reinit_big(dst), small); |
384 | 0 | } |
385 | | |
386 | | /* Convert to small representation while preserving the current number. Does |
387 | | * nothing if dst doesn't fit small representation. |
388 | | */ |
389 | | inline void isl_sioimath_try_demote(isl_sioimath_ptr dst) |
390 | 51.1M | { |
391 | 51.1M | mp_small small; |
392 | 51.1M | |
393 | 51.1M | if (isl_sioimath_is_small(*dst)) |
394 | 0 | return; |
395 | 51.1M | |
396 | 51.1M | if (mp_int_to_int(isl_sioimath_get_big(*dst), &small) != MP_OK) |
397 | 8.50M | return; |
398 | 42.6M | |
399 | 42.6M | if (ISL_SIOIMATH_SMALL_MIN <= small && small <= 36.7M ISL_SIOIMATH_SMALL_MAX36.7M ) |
400 | 42.6M | isl_sioimath_set_small(dst, small)26.2M ; |
401 | 42.6M | } |
402 | | |
403 | | /* Initialize an isl_int. The implicit value is 0 in small representation. |
404 | | */ |
405 | | inline void isl_sioimath_init(isl_sioimath_ptr dst) |
406 | 729M | { |
407 | 729M | *dst = isl_sioimath_encode_small(0); |
408 | 729M | } |
409 | | |
410 | | /* Free the resources taken by an isl_int. |
411 | | */ |
412 | | inline void isl_sioimath_clear(isl_sioimath_ptr dst) |
413 | 729M | { |
414 | 729M | if (isl_sioimath_is_small(*dst)) |
415 | 722M | return; |
416 | 6.67M | |
417 | 6.67M | mp_int_free(isl_sioimath_get_big(*dst)); |
418 | 6.67M | } |
419 | | |
420 | | /* Copy the value of one isl_int to another. |
421 | | */ |
422 | | inline void isl_sioimath_set(isl_sioimath_ptr dst, isl_sioimath_src val) |
423 | 898M | { |
424 | 898M | if (isl_sioimath_is_small(val)) { |
425 | 889M | isl_sioimath_set_small(dst, isl_sioimath_get_small(val)); |
426 | 889M | return; |
427 | 889M | } |
428 | 8.09M | |
429 | 8.09M | mp_int_copy(isl_sioimath_get_big(val), isl_sioimath_reinit_big(dst)); |
430 | 8.09M | } |
431 | | |
432 | | /* Store a signed long into an isl_int. |
433 | | */ |
434 | | inline void isl_sioimath_set_si(isl_sioimath_ptr dst, long val) |
435 | 306M | { |
436 | 306M | if (ISL_SIOIMATH_SMALL_MIN <= val && val <= ISL_SIOIMATH_SMALL_MAX) { |
437 | 306M | isl_sioimath_set_small(dst, val); |
438 | 306M | return; |
439 | 306M | } |
440 | 0 | |
441 | 0 | mp_int_set_value(isl_sioimath_reinit_big(dst), val); |
442 | 0 | } |
443 | | |
444 | | /* Store an unsigned long into an isl_int. |
445 | | */ |
446 | | inline void isl_sioimath_set_ui(isl_sioimath_ptr dst, unsigned long val) |
447 | 6.25k | { |
448 | 6.25k | if (val <= ISL_SIOIMATH_SMALL_MAX) { |
449 | 6.25k | isl_sioimath_set_small(dst, val); |
450 | 6.25k | return; |
451 | 6.25k | } |
452 | 0 | |
453 | 0 | mp_int_set_uvalue(isl_sioimath_reinit_big(dst), val); |
454 | 0 | } |
455 | | |
456 | | /* Return whether a number can be represented by a signed long. |
457 | | */ |
458 | | inline int isl_sioimath_fits_slong(isl_sioimath_src val) |
459 | 2.47k | { |
460 | 2.47k | mp_small dummy; |
461 | 2.47k | |
462 | 2.47k | if (isl_sioimath_is_small(val)) |
463 | 2.47k | return 1; |
464 | 0 | |
465 | 0 | return mp_int_to_int(isl_sioimath_get_big(val), &dummy) == MP_OK; |
466 | 0 | } |
467 | | |
468 | | /* Return a number as signed long. Result is undefined if the number cannot be |
469 | | * represented as long. |
470 | | */ |
471 | | inline long isl_sioimath_get_si(isl_sioimath_src val) |
472 | 3.12k | { |
473 | 3.12k | mp_small result; |
474 | 3.12k | |
475 | 3.12k | if (isl_sioimath_is_small(val)) |
476 | 3.12k | return isl_sioimath_get_small(val); |
477 | 0 | |
478 | 0 | mp_int_to_int(isl_sioimath_get_big(val), &result); |
479 | 0 | return result; |
480 | 0 | } |
481 | | |
482 | | /* Return whether a number can be represented as unsigned long. |
483 | | */ |
484 | | inline int isl_sioimath_fits_ulong(isl_sioimath_src val) |
485 | 5.91k | { |
486 | 5.91k | mp_usmall dummy; |
487 | 5.91k | |
488 | 5.91k | if (isl_sioimath_is_small(val)) |
489 | 5.91k | return isl_sioimath_get_small(val) >= 0; |
490 | 0 | |
491 | 0 | return mp_int_to_uint(isl_sioimath_get_big(val), &dummy) == MP_OK; |
492 | 0 | } |
493 | | |
494 | | /* Return a number as unsigned long. Result is undefined if the number cannot be |
495 | | * represented as unsigned long. |
496 | | */ |
497 | | inline unsigned long isl_sioimath_get_ui(isl_sioimath_src val) |
498 | 5.91k | { |
499 | 5.91k | mp_usmall result; |
500 | 5.91k | |
501 | 5.91k | if (isl_sioimath_is_small(val)) |
502 | 5.91k | return isl_sioimath_get_small(val); |
503 | 0 | |
504 | 0 | mp_int_to_uint(isl_sioimath_get_big(val), &result); |
505 | 0 | return result; |
506 | 0 | } |
507 | | |
508 | | /* Return a number as floating point value. |
509 | | */ |
510 | | inline double isl_sioimath_get_d(isl_sioimath_src val) |
511 | 0 | { |
512 | 0 | mp_int big; |
513 | 0 | double result = 0; |
514 | 0 | int i; |
515 | 0 |
|
516 | 0 | if (isl_sioimath_is_small(val)) |
517 | 0 | return isl_sioimath_get_small(val); |
518 | 0 | |
519 | 0 | big = isl_sioimath_get_big(val); |
520 | 0 | for (i = 0; i < big->used; ++i) |
521 | 0 | result = result * (double) ((uintmax_t) MP_DIGIT_MAX + 1) + |
522 | 0 | (double) big->digits[i]; |
523 | 0 |
|
524 | 0 | if (big->sign == MP_NEG) |
525 | 0 | result = -result; |
526 | 0 |
|
527 | 0 | return result; |
528 | 0 | } |
529 | | |
530 | | /* Format a number as decimal string. |
531 | | * |
532 | | * The largest possible string from small representation is 12 characters |
533 | | * ("-2147483647"). |
534 | | */ |
535 | | inline char *isl_sioimath_get_str(isl_sioimath_src val) |
536 | 17.7k | { |
537 | 17.7k | char *result; |
538 | 17.7k | |
539 | 17.7k | if (isl_sioimath_is_small(val)) { |
540 | 16.2k | result = malloc(12); |
541 | 16.2k | snprintf(result, 12, "%" PRIi32, isl_sioimath_get_small(val)); |
542 | 16.2k | return result; |
543 | 16.2k | } |
544 | 1.46k | |
545 | 1.46k | return impz_get_str(NULL, 10, isl_sioimath_get_big(val)); |
546 | 1.46k | } |
547 | | |
548 | | /* Return the absolute value. |
549 | | */ |
550 | | inline void isl_sioimath_abs(isl_sioimath_ptr dst, isl_sioimath_src arg) |
551 | 55.8M | { |
552 | 55.8M | if (isl_sioimath_is_small(arg)) { |
553 | 55.3M | isl_sioimath_set_small(dst, labs(isl_sioimath_get_small(arg))); |
554 | 55.3M | return; |
555 | 55.3M | } |
556 | 473k | |
557 | 473k | mp_int_abs(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst)); |
558 | 473k | } |
559 | | |
560 | | /* Return the negation of a number. |
561 | | */ |
562 | | inline void isl_sioimath_neg(isl_sioimath_ptr dst, isl_sioimath_src arg) |
563 | 381M | { |
564 | 381M | if (isl_sioimath_is_small(arg)) { |
565 | 380M | isl_sioimath_set_small(dst, -isl_sioimath_get_small(arg)); |
566 | 380M | return; |
567 | 380M | } |
568 | 819k | |
569 | 819k | mp_int_neg(isl_sioimath_get_big(arg), isl_sioimath_reinit_big(dst)); |
570 | 819k | } |
571 | | |
572 | | /* Swap two isl_ints. |
573 | | * |
574 | | * isl_sioimath can be copied bytewise; nothing depends on its address. It can |
575 | | * also be stored in a CPU register. |
576 | | */ |
577 | | inline void isl_sioimath_swap(isl_sioimath_ptr lhs, isl_sioimath_ptr rhs) |
578 | 139M | { |
579 | 139M | isl_sioimath tmp = *lhs; |
580 | 139M | *lhs = *rhs; |
581 | 139M | *rhs = tmp; |
582 | 139M | } |
583 | | |
584 | | /* Add an unsigned long to the number. |
585 | | * |
586 | | * On LP64 unsigned long exceeds the range of an int64_t, therefore we check in |
587 | | * advance whether small representation possibly overflows. |
588 | | */ |
589 | | inline void isl_sioimath_add_ui(isl_sioimath_ptr dst, isl_sioimath lhs, |
590 | | unsigned long rhs) |
591 | 1.51M | { |
592 | 1.51M | int32_t smalllhs; |
593 | 1.51M | isl_sioimath_scratchspace_t lhsscratch; |
594 | 1.51M | |
595 | 1.51M | if (isl_sioimath_decode_small(lhs, &smalllhs) && |
596 | 1.51M | (rhs <= (uint64_t) INT64_MAX - (uint64_t) 1.44M ISL_SIOIMATH_SMALL_MAX1.44M )) { |
597 | 1.44M | isl_sioimath_set_int64(dst, (int64_t) smalllhs + rhs); |
598 | 1.44M | return; |
599 | 1.44M | } |
600 | 70.2k | |
601 | 70.2k | impz_add_ui(isl_sioimath_reinit_big(dst), |
602 | 70.2k | isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs); |
603 | 70.2k | isl_sioimath_try_demote(dst); |
604 | 70.2k | } |
605 | | |
606 | | /* Subtract an unsigned long. |
607 | | * |
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. |
611 | | */ |
612 | | inline void isl_sioimath_sub_ui(isl_sioimath_ptr dst, isl_sioimath lhs, |
613 | | unsigned long rhs) |
614 | 1.61M | { |
615 | 1.61M | int32_t smalllhs; |
616 | 1.61M | isl_sioimath_scratchspace_t lhsscratch; |
617 | 1.61M | |
618 | 1.61M | if (isl_sioimath_decode_small(lhs, &smalllhs) && |
619 | 1.61M | (rhs < (uint64_t) INT64_MIN - (uint64_t) 1.49M ISL_SIOIMATH_SMALL_MIN1.49M )) { |
620 | 1.49M | isl_sioimath_set_int64(dst, (int64_t) smalllhs - rhs); |
621 | 1.49M | return; |
622 | 1.49M | } |
623 | 113k | |
624 | 113k | impz_sub_ui(isl_sioimath_reinit_big(dst), |
625 | 113k | isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs); |
626 | 113k | isl_sioimath_try_demote(dst); |
627 | 113k | } |
628 | | |
629 | | /* Sum of two isl_ints. |
630 | | */ |
631 | | inline void isl_sioimath_add(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
632 | | isl_sioimath_src rhs) |
633 | 556M | { |
634 | 556M | isl_sioimath_scratchspace_t scratchlhs, scratchrhs; |
635 | 556M | int32_t smalllhs, smallrhs; |
636 | 556M | |
637 | 556M | if (isl_sioimath_decode_small(lhs, &smalllhs) && |
638 | 556M | isl_sioimath_decode_small(rhs, &smallrhs)543M ) { |
639 | 541M | isl_sioimath_set_int64( |
640 | 541M | dst, (int64_t) smalllhs + (int64_t) smallrhs); |
641 | 541M | return; |
642 | 541M | } |
643 | 15.5M | |
644 | 15.5M | mp_int_add(isl_sioimath_bigarg_src(lhs, &scratchlhs), |
645 | 15.5M | isl_sioimath_bigarg_src(rhs, &scratchrhs), |
646 | 15.5M | isl_sioimath_reinit_big(dst)); |
647 | 15.5M | isl_sioimath_try_demote(dst); |
648 | 15.5M | } |
649 | | |
650 | | /* Subtract two isl_ints. |
651 | | */ |
652 | | inline void isl_sioimath_sub(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
653 | | isl_sioimath_src rhs) |
654 | 11.0M | { |
655 | 11.0M | isl_sioimath_scratchspace_t scratchlhs, scratchrhs; |
656 | 11.0M | int32_t smalllhs, smallrhs; |
657 | 11.0M | |
658 | 11.0M | if (isl_sioimath_decode_small(lhs, &smalllhs) && |
659 | 11.0M | isl_sioimath_decode_small(rhs, &smallrhs)10.6M ) { |
660 | 10.5M | isl_sioimath_set_int64( |
661 | 10.5M | dst, (int64_t) smalllhs - (int64_t) smallrhs); |
662 | 10.5M | return; |
663 | 10.5M | } |
664 | 536k | |
665 | 536k | mp_int_sub(isl_sioimath_bigarg_src(lhs, &scratchlhs), |
666 | 536k | isl_sioimath_bigarg_src(rhs, &scratchrhs), |
667 | 536k | isl_sioimath_reinit_big(dst)); |
668 | 536k | isl_sioimath_try_demote(dst); |
669 | 536k | } |
670 | | |
671 | | /* Multiply two isl_ints. |
672 | | */ |
673 | | inline void isl_sioimath_mul(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
674 | | isl_sioimath_src rhs) |
675 | 889M | { |
676 | 889M | isl_sioimath_scratchspace_t scratchlhs, scratchrhs; |
677 | 889M | int32_t smalllhs, smallrhs; |
678 | 889M | |
679 | 889M | if (isl_sioimath_decode_small(lhs, &smalllhs) && |
680 | 889M | isl_sioimath_decode_small(rhs, &smallrhs)872M ) { |
681 | 862M | isl_sioimath_set_int64( |
682 | 862M | dst, (int64_t) smalllhs * (int64_t) smallrhs); |
683 | 862M | return; |
684 | 862M | } |
685 | 27.0M | |
686 | 27.0M | mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs), |
687 | 27.0M | isl_sioimath_bigarg_src(rhs, &scratchrhs), |
688 | 27.0M | isl_sioimath_reinit_big(dst)); |
689 | 27.0M | isl_sioimath_try_demote(dst); |
690 | 27.0M | } |
691 | | |
692 | | /* Shift lhs by rhs bits to the left and store the result in dst. Effectively, |
693 | | * this operation computes 'lhs * 2^rhs'. |
694 | | */ |
695 | | inline void isl_sioimath_mul_2exp(isl_sioimath_ptr dst, isl_sioimath lhs, |
696 | | unsigned long rhs) |
697 | 5.91k | { |
698 | 5.91k | isl_sioimath_scratchspace_t scratchlhs; |
699 | 5.91k | int32_t smalllhs; |
700 | 5.91k | |
701 | 5.91k | if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= 32ul)) { |
702 | 1.98k | isl_sioimath_set_int64(dst, ((int64_t) smalllhs) << rhs); |
703 | 1.98k | return; |
704 | 1.98k | } |
705 | 3.93k | |
706 | 3.93k | mp_int_mul_pow2(isl_sioimath_bigarg_src(lhs, &scratchlhs), rhs, |
707 | 3.93k | isl_sioimath_reinit_big(dst)); |
708 | 3.93k | } |
709 | | |
710 | | /* Multiply an isl_int and a signed long. |
711 | | */ |
712 | | inline void isl_sioimath_mul_si(isl_sioimath_ptr dst, isl_sioimath lhs, |
713 | | signed long rhs) |
714 | 363 | { |
715 | 363 | isl_sioimath_scratchspace_t scratchlhs, scratchrhs; |
716 | 363 | int32_t smalllhs; |
717 | 363 | |
718 | 363 | if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs > LONG_MIN) && |
719 | 363 | (labs(rhs) <= UINT32_MAX)) { |
720 | 363 | isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs); |
721 | 363 | return; |
722 | 363 | } |
723 | 0 | |
724 | 0 | mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs), |
725 | 0 | isl_sioimath_siarg_src(rhs, &scratchrhs), |
726 | 0 | isl_sioimath_reinit_big(dst)); |
727 | 0 | isl_sioimath_try_demote(dst); |
728 | 0 | } |
729 | | |
730 | | /* Multiply an isl_int and an unsigned long. |
731 | | */ |
732 | | inline void isl_sioimath_mul_ui(isl_sioimath_ptr dst, isl_sioimath lhs, |
733 | | unsigned long rhs) |
734 | 443k | { |
735 | 443k | isl_sioimath_scratchspace_t scratchlhs, scratchrhs; |
736 | 443k | int32_t smalllhs; |
737 | 443k | |
738 | 443k | if (isl_sioimath_decode_small(lhs, &smalllhs) && (rhs <= UINT32_MAX)434k ) { |
739 | 434k | isl_sioimath_set_int64(dst, (int64_t) smalllhs * (int64_t) rhs); |
740 | 434k | return; |
741 | 434k | } |
742 | 9.75k | |
743 | 9.75k | mp_int_mul(isl_sioimath_bigarg_src(lhs, &scratchlhs), |
744 | 9.75k | isl_sioimath_uiarg_src(rhs, &scratchrhs), |
745 | 9.75k | isl_sioimath_reinit_big(dst)); |
746 | 9.75k | isl_sioimath_try_demote(dst); |
747 | 9.75k | } |
748 | | |
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 |
751 | | * special cases. |
752 | | * Note: 0^0 == 1 |
753 | | */ |
754 | | inline void isl_sioimath_pow_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
755 | | unsigned long rhs) |
756 | 0 | { |
757 | 0 | isl_sioimath_scratchspace_t scratchlhs, scratchrhs; |
758 | 0 | int32_t smalllhs; |
759 | 0 |
|
760 | 0 | switch (rhs) { |
761 | 0 | case 0: |
762 | 0 | isl_sioimath_set_small(dst, 1); |
763 | 0 | return; |
764 | 0 | case 1: |
765 | 0 | isl_sioimath_set(dst, lhs); |
766 | 0 | return; |
767 | 0 | case 2: |
768 | 0 | isl_sioimath_mul(dst, lhs, lhs); |
769 | 0 | return; |
770 | 0 | } |
771 | 0 | |
772 | 0 | if (isl_sioimath_decode_small(lhs, &smalllhs)) { |
773 | 0 | switch (smalllhs) { |
774 | 0 | case 0: |
775 | 0 | isl_sioimath_set_small(dst, 0); |
776 | 0 | return; |
777 | 0 | case 1: |
778 | 0 | isl_sioimath_set_small(dst, 1); |
779 | 0 | return; |
780 | 0 | case 2: |
781 | 0 | isl_sioimath_set_small(dst, 1); |
782 | 0 | isl_sioimath_mul_2exp(dst, *dst, rhs); |
783 | 0 | return; |
784 | 0 | default: |
785 | 0 | if ((MP_SMALL_MIN <= rhs) && (rhs <= MP_SMALL_MAX)) { |
786 | 0 | mp_int_expt_value(smalllhs, rhs, |
787 | 0 | isl_sioimath_reinit_big(dst)); |
788 | 0 | isl_sioimath_try_demote(dst); |
789 | 0 | return; |
790 | 0 | } |
791 | 0 | } |
792 | 0 | } |
793 | 0 | |
794 | 0 | mp_int_expt_full(isl_sioimath_bigarg_src(lhs, &scratchlhs), |
795 | 0 | isl_sioimath_uiarg_src(rhs, &scratchrhs), |
796 | 0 | isl_sioimath_reinit_big(dst)); |
797 | 0 | isl_sioimath_try_demote(dst); |
798 | 0 | } |
799 | | |
800 | | /* Fused multiply-add. |
801 | | */ |
802 | | inline void isl_sioimath_addmul(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
803 | | isl_sioimath_src rhs) |
804 | 543M | { |
805 | 543M | isl_sioimath tmp; |
806 | 543M | isl_sioimath_init(&tmp); |
807 | 543M | isl_sioimath_mul(&tmp, lhs, rhs); |
808 | 543M | isl_sioimath_add(dst, *dst, tmp); |
809 | 543M | isl_sioimath_clear(&tmp); |
810 | 543M | } |
811 | | |
812 | | /* Fused multiply-add with an unsigned long. |
813 | | */ |
814 | | inline void isl_sioimath_addmul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
815 | | unsigned long rhs) |
816 | 5.39k | { |
817 | 5.39k | isl_sioimath tmp; |
818 | 5.39k | isl_sioimath_init(&tmp); |
819 | 5.39k | isl_sioimath_mul_ui(&tmp, lhs, rhs); |
820 | 5.39k | isl_sioimath_add(dst, *dst, tmp); |
821 | 5.39k | isl_sioimath_clear(&tmp); |
822 | 5.39k | } |
823 | | |
824 | | /* Fused multiply-subtract. |
825 | | */ |
826 | | inline void isl_sioimath_submul(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
827 | | isl_sioimath_src rhs) |
828 | 9.59M | { |
829 | 9.59M | isl_sioimath tmp; |
830 | 9.59M | isl_sioimath_init(&tmp); |
831 | 9.59M | isl_sioimath_mul(&tmp, lhs, rhs); |
832 | 9.59M | isl_sioimath_sub(dst, *dst, tmp); |
833 | 9.59M | isl_sioimath_clear(&tmp); |
834 | 9.59M | } |
835 | | |
836 | | /* Fused multiply-add with an unsigned long. |
837 | | */ |
838 | | inline void isl_sioimath_submul_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
839 | | unsigned long rhs) |
840 | 196 | { |
841 | 196 | isl_sioimath tmp; |
842 | 196 | isl_sioimath_init(&tmp); |
843 | 196 | isl_sioimath_mul_ui(&tmp, lhs, rhs); |
844 | 196 | isl_sioimath_sub(dst, *dst, tmp); |
845 | 196 | isl_sioimath_clear(&tmp); |
846 | 196 | } |
847 | | |
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); |
852 | | |
853 | | /* Divide lhs by rhs, rounding to zero (Truncate). |
854 | | */ |
855 | | inline void isl_sioimath_tdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
856 | | isl_sioimath_src rhs) |
857 | 129M | { |
858 | 129M | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
859 | 129M | int32_t lhssmall, rhssmall; |
860 | 129M | |
861 | 129M | if (isl_sioimath_decode_small(lhs, &lhssmall) && |
862 | 129M | isl_sioimath_decode_small(rhs, &rhssmall)126M ) { |
863 | 125M | isl_sioimath_set_small(dst, lhssmall / rhssmall); |
864 | 125M | return; |
865 | 125M | } |
866 | 4.16M | |
867 | 4.16M | mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch), |
868 | 4.16M | isl_sioimath_bigarg_src(rhs, &rhsscratch), |
869 | 4.16M | isl_sioimath_reinit_big(dst), NULL); |
870 | 4.16M | isl_sioimath_try_demote(dst); |
871 | 4.16M | return; |
872 | 4.16M | } |
873 | | |
874 | | /* Divide lhs by an unsigned long rhs, rounding to zero (Truncate). |
875 | | */ |
876 | | inline void isl_sioimath_tdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
877 | | unsigned long rhs) |
878 | 420k | { |
879 | 420k | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
880 | 420k | int32_t lhssmall; |
881 | 420k | |
882 | 420k | if (isl_sioimath_is_small(lhs) && (rhs <= (unsigned long) INT32_MAX)409k ) { |
883 | 409k | lhssmall = isl_sioimath_get_small(lhs); |
884 | 409k | isl_sioimath_set_small(dst, lhssmall / (int32_t) rhs); |
885 | 409k | return; |
886 | 409k | } |
887 | 11.2k | |
888 | 11.2k | if (rhs <= MP_SMALL_MAX) { |
889 | 11.2k | mp_int_div_value(isl_sioimath_bigarg_src(lhs, &lhsscratch), rhs, |
890 | 11.2k | isl_sioimath_reinit_big(dst), NULL); |
891 | 11.2k | isl_sioimath_try_demote(dst); |
892 | 11.2k | return; |
893 | 11.2k | } |
894 | 0 | |
895 | 0 | mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch), |
896 | 0 | isl_sioimath_uiarg_src(rhs, &rhsscratch), |
897 | 0 | isl_sioimath_reinit_big(dst), NULL); |
898 | 0 | isl_sioimath_try_demote(dst); |
899 | 0 | } |
900 | | |
901 | | /* Divide lhs by rhs, rounding to positive infinity (Ceil). |
902 | | */ |
903 | | inline void isl_sioimath_cdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
904 | | isl_sioimath_src rhs) |
905 | 792k | { |
906 | 792k | int32_t lhssmall, rhssmall; |
907 | 792k | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
908 | 792k | int32_t q; |
909 | 792k | |
910 | 792k | if (isl_sioimath_decode_small(lhs, &lhssmall) && |
911 | 792k | isl_sioimath_decode_small(rhs, &rhssmall)658k ) { |
912 | 658k | if ((lhssmall >= 0) && (rhssmall >= 0)418k ) |
913 | 418k | q = ((int64_t) lhssmall + (int64_t) rhssmall - 1) / |
914 | 418k | rhssmall; |
915 | 240k | else if ((lhssmall < 0) && (rhssmall < 0)) |
916 | 0 | q = ((int64_t) lhssmall + (int64_t) rhssmall + 1) / |
917 | 0 | rhssmall; |
918 | 240k | else |
919 | 240k | q = lhssmall / rhssmall; |
920 | 658k | isl_sioimath_set_small(dst, q); |
921 | 658k | return; |
922 | 658k | } |
923 | 134k | |
924 | 134k | impz_cdiv_q(isl_sioimath_reinit_big(dst), |
925 | 134k | isl_sioimath_bigarg_src(lhs, &lhsscratch), |
926 | 134k | isl_sioimath_bigarg_src(rhs, &rhsscratch)); |
927 | 134k | isl_sioimath_try_demote(dst); |
928 | 134k | } |
929 | | |
930 | | /* Compute the division of lhs by a rhs of type unsigned long, rounding towards |
931 | | * positive infinity (Ceil). |
932 | | */ |
933 | | inline void isl_sioimath_cdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
934 | | unsigned long rhs) |
935 | 363 | { |
936 | 363 | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
937 | 363 | int32_t lhssmall, q; |
938 | 363 | |
939 | 363 | if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)) { |
940 | 363 | if (lhssmall >= 0) |
941 | 152 | q = ((int64_t) lhssmall + ((int64_t) rhs - 1)) / |
942 | 152 | (int64_t) rhs; |
943 | 211 | else |
944 | 211 | q = lhssmall / (int32_t) rhs; |
945 | 363 | isl_sioimath_set_small(dst, q); |
946 | 363 | return; |
947 | 363 | } |
948 | 0 | |
949 | 0 | impz_cdiv_q(isl_sioimath_reinit_big(dst), |
950 | 0 | isl_sioimath_bigarg_src(lhs, &lhsscratch), |
951 | 0 | isl_sioimath_uiarg_src(rhs, &rhsscratch)); |
952 | 0 | isl_sioimath_try_demote(dst); |
953 | 0 | } |
954 | | |
955 | | /* Divide lhs by rhs, rounding to negative infinity (Floor). |
956 | | */ |
957 | | inline void isl_sioimath_fdiv_q(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
958 | | isl_sioimath_src rhs) |
959 | 1.35M | { |
960 | 1.35M | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
961 | 1.35M | int32_t lhssmall, rhssmall; |
962 | 1.35M | int32_t q; |
963 | 1.35M | |
964 | 1.35M | if (isl_sioimath_decode_small(lhs, &lhssmall) && |
965 | 1.35M | isl_sioimath_decode_small(rhs, &rhssmall)1.08M ) { |
966 | 1.07M | if ((lhssmall < 0) && (rhssmall >= 0)311k ) |
967 | 311k | q = ((int64_t) lhssmall - ((int64_t) rhssmall - 1)) / |
968 | 311k | rhssmall; |
969 | 762k | else if ((lhssmall >= 0) && (rhssmall < 0)) |
970 | 0 | q = ((int64_t) lhssmall - ((int64_t) rhssmall + 1)) / |
971 | 0 | rhssmall; |
972 | 762k | else |
973 | 762k | q = lhssmall / rhssmall; |
974 | 1.07M | isl_sioimath_set_small(dst, q); |
975 | 1.07M | return; |
976 | 1.07M | } |
977 | 281k | |
978 | 281k | impz_fdiv_q(isl_sioimath_reinit_big(dst), |
979 | 281k | isl_sioimath_bigarg_src(lhs, &lhsscratch), |
980 | 281k | isl_sioimath_bigarg_src(rhs, &rhsscratch)); |
981 | 281k | isl_sioimath_try_demote(dst); |
982 | 281k | } |
983 | | |
984 | | /* Compute the division of lhs by a rhs of type unsigned long, rounding towards |
985 | | * negative infinity (Floor). |
986 | | */ |
987 | | inline void isl_sioimath_fdiv_q_ui(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
988 | | unsigned long rhs) |
989 | 154k | { |
990 | 154k | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
991 | 154k | int32_t lhssmall, q; |
992 | 154k | |
993 | 154k | if (isl_sioimath_decode_small(lhs, &lhssmall) && (rhs <= INT32_MAX)141k ) { |
994 | 141k | if (lhssmall >= 0) |
995 | 120k | q = (uint32_t) lhssmall / rhs; |
996 | 21.3k | else |
997 | 21.3k | q = ((int64_t) lhssmall - ((int64_t) rhs - 1)) / |
998 | 21.3k | (int64_t) rhs; |
999 | 141k | isl_sioimath_set_small(dst, q); |
1000 | 141k | return; |
1001 | 141k | } |
1002 | 12.9k | |
1003 | 12.9k | impz_fdiv_q(isl_sioimath_reinit_big(dst), |
1004 | 12.9k | isl_sioimath_bigarg_src(lhs, &lhsscratch), |
1005 | 12.9k | isl_sioimath_uiarg_src(rhs, &rhsscratch)); |
1006 | 12.9k | isl_sioimath_try_demote(dst); |
1007 | 12.9k | } |
1008 | | |
1009 | | /* Get the remainder of: lhs divided by rhs rounded towards negative infinite |
1010 | | * (Floor). |
1011 | | */ |
1012 | | inline void isl_sioimath_fdiv_r(isl_sioimath_ptr dst, isl_sioimath_src lhs, |
1013 | | isl_sioimath_src rhs) |
1014 | 216k | { |
1015 | 216k | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
1016 | 216k | int64_t lhssmall, rhssmall; |
1017 | 216k | int32_t r; |
1018 | 216k | |
1019 | 216k | if (isl_sioimath_is_small(lhs) && isl_sioimath_is_small(rhs)213k ) { |
1020 | 208k | lhssmall = isl_sioimath_get_small(lhs); |
1021 | 208k | rhssmall = isl_sioimath_get_small(rhs); |
1022 | 208k | r = (rhssmall + lhssmall % rhssmall) % rhssmall; |
1023 | 208k | isl_sioimath_set_small(dst, r); |
1024 | 208k | return; |
1025 | 208k | } |
1026 | 7.19k | |
1027 | 7.19k | impz_fdiv_r(isl_sioimath_reinit_big(dst), |
1028 | 7.19k | isl_sioimath_bigarg_src(lhs, &lhsscratch), |
1029 | 7.19k | isl_sioimath_bigarg_src(rhs, &rhsscratch)); |
1030 | 7.19k | isl_sioimath_try_demote(dst); |
1031 | 7.19k | } |
1032 | | |
1033 | | void isl_sioimath_read(isl_sioimath_ptr dst, const char *str); |
1034 | | |
1035 | | /* Return: |
1036 | | * +1 for a positive number |
1037 | | * -1 for a negative number |
1038 | | * 0 if the number is zero |
1039 | | */ |
1040 | | inline int isl_sioimath_sgn(isl_sioimath_src arg) |
1041 | 2.19G | { |
1042 | 2.19G | int32_t small; |
1043 | 2.19G | |
1044 | 2.19G | if (isl_sioimath_decode_small(arg, &small)) |
1045 | 2.18G | return (small > 0) - (small < 0); |
1046 | 13.4M | |
1047 | 13.4M | return mp_int_compare_zero(isl_sioimath_get_big(arg)); |
1048 | 13.4M | } |
1049 | | |
1050 | | /* Return: |
1051 | | * +1 if lhs > rhs |
1052 | | * -1 if lhs < rhs |
1053 | | * 0 if lhs = rhs |
1054 | | */ |
1055 | | inline int isl_sioimath_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs) |
1056 | 258M | { |
1057 | 258M | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
1058 | 258M | int32_t lhssmall, rhssmall; |
1059 | 258M | |
1060 | 258M | if (isl_sioimath_decode_small(lhs, &lhssmall) && |
1061 | 258M | isl_sioimath_decode_small(rhs, &rhssmall)257M ) |
1062 | 257M | return (lhssmall > rhssmall) - (lhssmall < rhssmall); |
1063 | 488k | |
1064 | 488k | if (isl_sioimath_decode_small(rhs, &rhssmall)) |
1065 | 179k | return mp_int_compare_value( |
1066 | 179k | isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall); |
1067 | 309k | |
1068 | 309k | if (isl_sioimath_decode_small(lhs, &lhssmall)) |
1069 | 35.0k | return -mp_int_compare_value( |
1070 | 35.0k | isl_sioimath_bigarg_src(rhs, &rhsscratch), lhssmall); |
1071 | 274k | |
1072 | 274k | return mp_int_compare( |
1073 | 274k | isl_sioimath_get_big(lhs), isl_sioimath_get_big(rhs)); |
1074 | 274k | } |
1075 | | |
1076 | | /* As isl_sioimath_cmp, but with signed long rhs. |
1077 | | */ |
1078 | | inline int isl_sioimath_cmp_si(isl_sioimath_src lhs, signed long rhs) |
1079 | 238M | { |
1080 | 238M | int32_t lhssmall; |
1081 | 238M | |
1082 | 238M | if (isl_sioimath_decode_small(lhs, &lhssmall)) |
1083 | 235M | return (lhssmall > rhs) - (lhssmall < rhs); |
1084 | 3.27M | |
1085 | 3.27M | return mp_int_compare_value(isl_sioimath_get_big(lhs), rhs); |
1086 | 3.27M | } |
1087 | | |
1088 | | /* Return: |
1089 | | * +1 if |lhs| > |rhs| |
1090 | | * -1 if |lhs| < |rhs| |
1091 | | * 0 if |lhs| = |rhs| |
1092 | | */ |
1093 | | inline int isl_sioimath_abs_cmp(isl_sioimath_src lhs, isl_sioimath_src rhs) |
1094 | 71.9M | { |
1095 | 71.9M | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
1096 | 71.9M | int32_t lhssmall, rhssmall; |
1097 | 71.9M | |
1098 | 71.9M | if (isl_sioimath_decode_small(lhs, &lhssmall) && |
1099 | 71.9M | isl_sioimath_decode_small(rhs, &rhssmall)68.5M ) { |
1100 | 68.2M | lhssmall = labs(lhssmall); |
1101 | 68.2M | rhssmall = labs(rhssmall); |
1102 | 68.2M | return (lhssmall > rhssmall) - (lhssmall < rhssmall); |
1103 | 68.2M | } |
1104 | 3.64M | |
1105 | 3.64M | return mp_int_compare_unsigned( |
1106 | 3.64M | isl_sioimath_bigarg_src(lhs, &lhsscratch), |
1107 | 3.64M | isl_sioimath_bigarg_src(rhs, &rhsscratch)); |
1108 | 3.64M | } |
1109 | | |
1110 | | /* Return whether lhs is divisible by rhs. |
1111 | | * In particular, can rhs be multiplied by some integer to result in lhs? |
1112 | | * If rhs is zero, then this means lhs has to be zero too. |
1113 | | */ |
1114 | | inline int isl_sioimath_is_divisible_by(isl_sioimath_src lhs, |
1115 | | isl_sioimath_src rhs) |
1116 | 7.19M | { |
1117 | 7.19M | isl_sioimath_scratchspace_t lhsscratch, rhsscratch; |
1118 | 7.19M | int32_t lhssmall, rhssmall; |
1119 | 7.19M | mpz_t rem; |
1120 | 7.19M | int cmp; |
1121 | 7.19M | |
1122 | 7.19M | if (isl_sioimath_sgn(rhs) == 0) |
1123 | 0 | return isl_sioimath_sgn(lhs) == 0; |
1124 | 7.19M | |
1125 | 7.19M | if (isl_sioimath_decode_small(lhs, &lhssmall) && |
1126 | 7.19M | isl_sioimath_decode_small(rhs, &rhssmall)7.13M ) |
1127 | 7.12M | return lhssmall % rhssmall == 0; |
1128 | 76.2k | |
1129 | 76.2k | if (isl_sioimath_decode_small(rhs, &rhssmall)) |
1130 | 57.4k | return mp_int_divisible_value( |
1131 | 57.4k | isl_sioimath_bigarg_src(lhs, &lhsscratch), rhssmall); |
1132 | 18.7k | |
1133 | 18.7k | mp_int_init(&rem); |
1134 | 18.7k | mp_int_div(isl_sioimath_bigarg_src(lhs, &lhsscratch), |
1135 | 18.7k | isl_sioimath_bigarg_src(rhs, &rhsscratch), NULL, &rem); |
1136 | 18.7k | cmp = mp_int_compare_zero(&rem); |
1137 | 18.7k | mp_int_clear(&rem); |
1138 | 18.7k | return cmp == 0; |
1139 | 18.7k | } |
1140 | | |
1141 | | /* Return a hash code of an isl_sioimath. |
1142 | | * The hash code for a number in small and big representation must be identical |
1143 | | * on the same machine because small representation if not obligatory if fits. |
1144 | | */ |
1145 | | inline uint32_t isl_sioimath_hash(isl_sioimath_src arg, uint32_t hash) |
1146 | 51.9M | { |
1147 | 51.9M | int32_t small; |
1148 | 51.9M | int i; |
1149 | 51.9M | uint32_t num; |
1150 | 51.9M | mp_digit digits[(sizeof(uint32_t) + sizeof(mp_digit) - 1) / |
1151 | 51.9M | sizeof(mp_digit)]; |
1152 | 51.9M | mp_size used; |
1153 | 51.9M | const unsigned char *digitdata = (const unsigned char *) &digits; |
1154 | 51.9M | |
1155 | 51.9M | if (isl_sioimath_decode_small(arg, &small)) { |
1156 | 51.6M | if (small < 0) |
1157 | 51.6M | isl_hash_byte26.4M (hash, 0xFF); |
1158 | 51.6M | num = labs(small); |
1159 | 51.6M | |
1160 | 51.6M | isl_siomath_uint32_to_digits(num, digits, &used); |
1161 | 258M | for (i = 0; i < used * sizeof(mp_digit); i += 1206M ) |
1162 | 206M | isl_hash_byte(hash, digitdata[i]); |
1163 | 51.6M | return hash; |
1164 | 51.6M | } |
1165 | 261k | |
1166 | 261k | return isl_imath_hash(isl_sioimath_get_big(arg), hash); |
1167 | 261k | } |
1168 | | |
1169 | | /* Return the number of digits in a number of the given base or more, i.e. the |
1170 | | * string length without sign and null terminator. |
1171 | | * |
1172 | | * Current implementation for small representation returns the maximal number |
1173 | | * of binary digits in that representation, which can be much larger than the |
1174 | | * smallest possible solution. |
1175 | | */ |
1176 | | inline size_t isl_sioimath_sizeinbase(isl_sioimath_src arg, int base) |
1177 | 3.89k | { |
1178 | 3.89k | int32_t small; |
1179 | 3.89k | |
1180 | 3.89k | if (isl_sioimath_decode_small(arg, &small)) |
1181 | 3.78k | return sizeof(int32_t) * CHAR_BIT - 1; |
1182 | 110 | |
1183 | 110 | return impz_sizeinbase(isl_sioimath_get_big(arg), base); |
1184 | 110 | } |
1185 | | |
1186 | | void isl_sioimath_print(FILE *out, isl_sioimath_src i, int width); |
1187 | | void isl_sioimath_dump(isl_sioimath_src arg); |
1188 | | |
1189 | | typedef isl_sioimath isl_int[1]; |
1190 | 204M | #define isl_int_init(i) isl_sioimath_init((i)) |
1191 | 176M | #define isl_int_clear(i) isl_sioimath_clear((i)) |
1192 | | |
1193 | 899M | #define isl_int_set(r, i) isl_sioimath_set((r), *(i)) |
1194 | 310M | #define isl_int_set_si(r, i) isl_sioimath_set_si((r), i) |
1195 | 12.5k | #define isl_int_set_ui(r, i) isl_sioimath_set_ui((r), i) |
1196 | 2.47k | #define isl_int_fits_slong(r) isl_sioimath_fits_slong(*(r)) |
1197 | 3.12k | #define isl_int_get_si(r) isl_sioimath_get_si(*(r)) |
1198 | 5.91k | #define isl_int_fits_ulong(r) isl_sioimath_fits_ulong(*(r)) |
1199 | 5.91k | #define isl_int_get_ui(r) isl_sioimath_get_ui(*(r)) |
1200 | 0 | #define isl_int_get_d(r) isl_sioimath_get_d(*(r)) |
1201 | 17.7k | #define isl_int_get_str(r) isl_sioimath_get_str(*(r)) |
1202 | 107M | #define isl_int_abs(r, i) isl_sioimath_abs((r), *(i)) |
1203 | 400M | #define isl_int_neg(r, i) isl_sioimath_neg((r), *(i)) |
1204 | 96.7M | #define isl_int_swap(i, j) isl_sioimath_swap((i), (j)) |
1205 | 49.9M | #define isl_int_swap_or_set(i, j) isl_sioimath_swap((i), (j)) |
1206 | 1.51M | #define isl_int_add_ui(r, i, j) isl_sioimath_add_ui((r), *(i), j) |
1207 | 1.61M | #define isl_int_sub_ui(r, i, j) isl_sioimath_sub_ui((r), *(i), j) |
1208 | | |
1209 | 13.6M | #define isl_int_add(r, i, j) isl_sioimath_add((r), *(i), *(j)) |
1210 | 1.49M | #define isl_int_sub(r, i, j) isl_sioimath_sub((r), *(i), *(j)) |
1211 | 510M | #define isl_int_mul(r, i, j) isl_sioimath_mul((r), *(i), *(j)) |
1212 | 5.91k | #define isl_int_mul_2exp(r, i, j) isl_sioimath_mul_2exp((r), *(i), j) |
1213 | 363 | #define isl_int_mul_si(r, i, j) isl_sioimath_mul_si((r), *(i), j) |
1214 | 756k | #define isl_int_mul_ui(r, i, j) isl_sioimath_mul_ui((r), *(i), j) |
1215 | 0 | #define isl_int_pow_ui(r, i, j) isl_sioimath_pow_ui((r), *(i), j) |
1216 | 543M | #define isl_int_addmul(r, i, j) isl_sioimath_addmul((r), *(i), *(j)) |
1217 | 10.7k | #define isl_int_addmul_ui(r, i, j) isl_sioimath_addmul_ui((r), *(i), j) |
1218 | 9.62M | #define isl_int_submul(r, i, j) isl_sioimath_submul((r), *(i), *(j)) |
1219 | 392 | #define isl_int_submul_ui(r, i, j) isl_sioimath_submul_ui((r), *(i), j) |
1220 | | |
1221 | 44.2M | #define isl_int_gcd(r, i, j) isl_sioimath_gcd((r), *(i), *(j)) |
1222 | 24.2M | #define isl_int_lcm(r, i, j) isl_sioimath_lcm((r), *(i), *(j)) |
1223 | 129M | #define isl_int_divexact(r, i, j) isl_sioimath_tdiv_q((r), *(i), *(j)) |
1224 | 420k | #define isl_int_divexact_ui(r, i, j) isl_sioimath_tdiv_q_ui((r), *(i), j) |
1225 | 0 | #define isl_int_tdiv_q(r, i, j) isl_sioimath_tdiv_q((r), *(i), *(j)) |
1226 | 685k | #define isl_int_cdiv_q(r, i, j) isl_sioimath_cdiv_q((r), *(i), *(j)) |
1227 | 639 | #define isl_int_cdiv_q_ui(r, i, j) isl_sioimath_cdiv_q_ui((r), *(i), j) |
1228 | 1.44M | #define isl_int_fdiv_q(r, i, j) isl_sioimath_fdiv_q((r), *(i), *(j)) |
1229 | 221k | #define isl_int_fdiv_r(r, i, j) isl_sioimath_fdiv_r((r), *(i), *(j)) |
1230 | 154k | #define isl_int_fdiv_q_ui(r, i, j) isl_sioimath_fdiv_q_ui((r), *(i), j) |
1231 | | |
1232 | 10.7k | #define isl_int_read(r, s) isl_sioimath_read((r), s) |
1233 | 2.19G | #define isl_int_sgn(i) isl_sioimath_sgn(*(i)) |
1234 | 27.6M | #define isl_int_cmp(i, j) isl_sioimath_cmp(*(i), *(j)) |
1235 | 238M | #define isl_int_cmp_si(i, si) isl_sioimath_cmp_si(*(i), si) |
1236 | 3.54M | #define isl_int_eq(i, j) (isl_sioimath_cmp(*(i), *(j)) == 0) |
1237 | 211M | #define isl_int_ne(i, j) (isl_sioimath_cmp(*(i), *(j)) != 0) |
1238 | 14.9M | #define isl_int_lt(i, j) (isl_sioimath_cmp(*(i), *(j)) < 0) |
1239 | 121k | #define isl_int_le(i, j) (isl_sioimath_cmp(*(i), *(j)) <= 0) |
1240 | 867k | #define isl_int_gt(i, j) (isl_sioimath_cmp(*(i), *(j)) > 0) |
1241 | 75.8k | #define isl_int_ge(i, j) (isl_sioimath_cmp(*(i), *(j)) >= 0) |
1242 | 1.60M | #define isl_int_abs_cmp(i, j) isl_sioimath_abs_cmp(*(i), *(j)) |
1243 | 65.7k | #define isl_int_abs_eq(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) == 0) |
1244 | 7.04M | #define isl_int_abs_ne(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) != 0) |
1245 | 60.9M | #define isl_int_abs_lt(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) < 0) |
1246 | 1.26M | #define isl_int_abs_gt(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) > 0) |
1247 | 1.30M | #define isl_int_abs_ge(i, j) (isl_sioimath_abs_cmp(*(i), *(j)) >= 0) |
1248 | 7.19M | #define isl_int_is_divisible_by(i, j) isl_sioimath_is_divisible_by(*(i), *(j)) |
1249 | | |
1250 | 51.9M | #define isl_int_hash(v, h) isl_sioimath_hash(*(v), h) |
1251 | 17.7k | #define isl_int_free_str(s) free(s) |
1252 | 0 | #define isl_int_print(out, i, width) isl_sioimath_print(out, *(i), width) |
1253 | | |
1254 | | #endif /* ISL_INT_SIOIMATH_H */ |