| 1 | /* |
| 2 | Name: gmp_compat.c |
| 3 | Purpose: Provide GMP compatiable routines for imath library |
| 4 | Author: David Peixotto |
| 5 | |
| 6 | Copyright (c) 2012 Qualcomm Innovation Center, Inc. All rights reserved. |
| 7 | |
| 8 | Permission is hereby granted, free of charge, to any person obtaining a copy |
| 9 | of this software and associated documentation files (the "Software"), to deal |
| 10 | in the Software without restriction, including without limitation the rights |
| 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 12 | copies of the Software, and to permit persons to whom the Software is |
| 13 | furnished to do so, subject to the following conditions: |
| 14 | |
| 15 | The above copyright notice and this permission notice shall be included in |
| 16 | all copies or substantial portions of the Software. |
| 17 | |
| 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 24 | SOFTWARE. |
| 25 | */ |
| 26 | #include "gmp_compat.h" |
| 27 | #include <assert.h> |
| 28 | #include <ctype.h> |
| 29 | #include <stdio.h> |
| 30 | #include <stdlib.h> |
| 31 | #include <string.h> |
| 32 | |
| 33 | #if defined(_MSC_VER) |
| 34 | #include <BaseTsd.h> |
| 35 | typedef SSIZE_T ssize_t; |
| 36 | #else |
| 37 | #include <sys/types.h> |
| 38 | #endif |
| 39 | |
| 40 | #ifdef NDEBUG |
| 41 | #define CHECK(res) (res) |
| 42 | #else |
| 43 | #define CHECK(res) assert(((res) == MP_OK) && "expected MP_OK") |
| 44 | #endif |
| 45 | |
| 46 | /* *(signed char *)&endian_test will thus either be: |
| 47 | * 0b00000001 = 1 on big-endian |
| 48 | * 0b11111111 = -1 on little-endian */ |
| 49 | static const uint16_t endian_test = 0x1FF; |
| 50 | #define HOST_ENDIAN (*(signed char *)&endian_test) |
| 51 | |
| 52 | /************************************************************************* |
| 53 | * |
| 54 | * Functions with direct translations |
| 55 | * |
| 56 | *************************************************************************/ |
| 57 | /* gmp: mpq_clear */ |
| 58 | void GMPQAPI(clear)(mp_rat x) { mp_rat_clear(r: x); } |
| 59 | |
| 60 | /* gmp: mpq_cmp */ |
| 61 | int GMPQAPI(cmp)(mp_rat op1, mp_rat op2) { return mp_rat_compare(a: op1, b: op2); } |
| 62 | |
| 63 | /* gmp: mpq_init */ |
| 64 | void GMPQAPI(init)(mp_rat x) { CHECK(mp_rat_init(x)); } |
| 65 | |
| 66 | /* gmp: mpq_mul */ |
| 67 | void GMPQAPI(mul)(mp_rat product, mp_rat multiplier, mp_rat multiplicand) { |
| 68 | CHECK(mp_rat_mul(multiplier, multiplicand, product)); |
| 69 | } |
| 70 | |
| 71 | /* gmp: mpq_set */ |
| 72 | void GMPQAPI(set)(mp_rat rop, mp_rat op) { CHECK(mp_rat_copy(op, rop)); } |
| 73 | |
| 74 | /* gmp: mpz_abs */ |
| 75 | void GMPZAPI(abs)(mp_int rop, mp_int op) { CHECK(mp_int_abs(op, rop)); } |
| 76 | |
| 77 | /* gmp: mpz_add */ |
| 78 | void GMPZAPI(add)(mp_int rop, mp_int op1, mp_int op2) { |
| 79 | CHECK(mp_int_add(op1, op2, rop)); |
| 80 | } |
| 81 | |
| 82 | /* gmp: mpz_clear */ |
| 83 | void GMPZAPI(clear)(mp_int x) { mp_int_clear(z: x); } |
| 84 | |
| 85 | /* gmp: mpz_cmp_si */ |
| 86 | int GMPZAPI(cmp_si)(mp_int op1, long op2) { |
| 87 | return mp_int_compare_value(z: op1, v: op2); |
| 88 | } |
| 89 | |
| 90 | /* gmp: mpz_cmpabs */ |
| 91 | int GMPZAPI(cmpabs)(mp_int op1, mp_int op2) { |
| 92 | return mp_int_compare_unsigned(a: op1, b: op2); |
| 93 | } |
| 94 | |
| 95 | /* gmp: mpz_cmp */ |
| 96 | int GMPZAPI(cmp)(mp_int op1, mp_int op2) { return mp_int_compare(a: op1, b: op2); } |
| 97 | |
| 98 | /* gmp: mpz_init */ |
| 99 | void GMPZAPI(init)(mp_int x) { CHECK(mp_int_init(x)); } |
| 100 | |
| 101 | /* gmp: mpz_mul */ |
| 102 | void GMPZAPI(mul)(mp_int rop, mp_int op1, mp_int op2) { |
| 103 | CHECK(mp_int_mul(op1, op2, rop)); |
| 104 | } |
| 105 | |
| 106 | /* gmp: mpz_neg */ |
| 107 | void GMPZAPI(neg)(mp_int rop, mp_int op) { CHECK(mp_int_neg(op, rop)); } |
| 108 | |
| 109 | /* gmp: mpz_set_si */ |
| 110 | void GMPZAPI(set_si)(mp_int rop, long op) { CHECK(mp_int_set_value(rop, op)); } |
| 111 | |
| 112 | /* gmp: mpz_set */ |
| 113 | void GMPZAPI(set)(mp_int rop, mp_int op) { CHECK(mp_int_copy(op, rop)); } |
| 114 | |
| 115 | /* gmp: mpz_sub */ |
| 116 | void GMPZAPI(sub)(mp_int rop, mp_int op1, mp_int op2) { |
| 117 | CHECK(mp_int_sub(op1, op2, rop)); |
| 118 | } |
| 119 | |
| 120 | /* gmp: mpz_swap */ |
| 121 | void GMPZAPI(swap)(mp_int rop1, mp_int rop2) { mp_int_swap(a: rop1, c: rop2); } |
| 122 | |
| 123 | /* gmp: mpq_sgn */ |
| 124 | int GMPQAPI(sgn)(mp_rat op) { return mp_rat_compare_zero(r: op); } |
| 125 | |
| 126 | /* gmp: mpz_sgn */ |
| 127 | int GMPZAPI(sgn)(mp_int op) { return mp_int_compare_zero(z: op); } |
| 128 | |
| 129 | /* gmp: mpq_set_ui */ |
| 130 | void GMPQAPI(set_ui)(mp_rat rop, unsigned long op1, unsigned long op2) { |
| 131 | CHECK(mp_rat_set_uvalue(rop, op1, op2)); |
| 132 | } |
| 133 | |
| 134 | /* gmp: mpz_set_ui */ |
| 135 | void GMPZAPI(set_ui)(mp_int rop, unsigned long op) { |
| 136 | CHECK(mp_int_set_uvalue(rop, op)); |
| 137 | } |
| 138 | |
| 139 | /* gmp: mpq_den_ref */ |
| 140 | mp_int GMPQAPI(denref)(mp_rat op) { return mp_rat_denom_ref(r: op); } |
| 141 | |
| 142 | /* gmp: mpq_num_ref */ |
| 143 | mp_int GMPQAPI(numref)(mp_rat op) { return mp_rat_numer_ref(r: op); } |
| 144 | |
| 145 | /* gmp: mpq_canonicalize */ |
| 146 | void GMPQAPI(canonicalize)(mp_rat op) { CHECK(mp_rat_reduce(op)); } |
| 147 | |
| 148 | /* |
| 149 | * Functions that can be implemented as a combination of imath functions |
| 150 | */ |
| 151 | |
| 152 | /* gmp: mpz_addmul */ |
| 153 | /* gmp: rop = rop + (op1 * op2) */ |
| 154 | void GMPZAPI(addmul)(mp_int rop, mp_int op1, mp_int op2) { |
| 155 | mpz_t tempz; |
| 156 | mp_int temp = &tempz; |
| 157 | mp_int_init(z: temp); |
| 158 | |
| 159 | CHECK(mp_int_mul(op1, op2, temp)); |
| 160 | CHECK(mp_int_add(rop, temp, rop)); |
| 161 | mp_int_clear(z: temp); |
| 162 | } |
| 163 | |
| 164 | /* gmp: mpz_divexact */ |
| 165 | /* gmp: only produces correct results when d divides n */ |
| 166 | void GMPZAPI(divexact)(mp_int q, mp_int n, mp_int d) { |
| 167 | CHECK(mp_int_div(n, d, q, NULL)); |
| 168 | } |
| 169 | |
| 170 | /* gmp: mpz_divisible_p */ |
| 171 | /* gmp: return 1 if d divides n, 0 otherwise */ |
| 172 | /* gmp: 0 is considered to divide only 0 */ |
| 173 | int GMPZAPI(divisible_p)(mp_int n, mp_int d) { |
| 174 | /* variables to hold remainder */ |
| 175 | mpz_t rz; |
| 176 | mp_int r = &rz; |
| 177 | int r_is_zero; |
| 178 | |
| 179 | /* check for d = 0 */ |
| 180 | int n_is_zero = mp_int_compare_zero(z: n) == 0; |
| 181 | int d_is_zero = mp_int_compare_zero(z: d) == 0; |
| 182 | if (d_is_zero) return n_is_zero; |
| 183 | |
| 184 | /* return true if remainder is 0 */ |
| 185 | CHECK(mp_int_init(r)); |
| 186 | CHECK(mp_int_div(n, d, NULL, r)); |
| 187 | r_is_zero = mp_int_compare_zero(z: r) == 0; |
| 188 | mp_int_clear(z: r); |
| 189 | |
| 190 | return r_is_zero; |
| 191 | } |
| 192 | |
| 193 | /* gmp: mpz_submul */ |
| 194 | /* gmp: rop = rop - (op1 * op2) */ |
| 195 | void GMPZAPI(submul)(mp_int rop, mp_int op1, mp_int op2) { |
| 196 | mpz_t tempz; |
| 197 | mp_int temp = &tempz; |
| 198 | mp_int_init(z: temp); |
| 199 | |
| 200 | CHECK(mp_int_mul(op1, op2, temp)); |
| 201 | CHECK(mp_int_sub(rop, temp, rop)); |
| 202 | |
| 203 | mp_int_clear(z: temp); |
| 204 | } |
| 205 | |
| 206 | /* gmp: mpz_add_ui */ |
| 207 | void GMPZAPI(add_ui)(mp_int rop, mp_int op1, unsigned long op2) { |
| 208 | mpz_t tempz; |
| 209 | mp_int temp = &tempz; |
| 210 | CHECK(mp_int_init_uvalue(temp, op2)); |
| 211 | |
| 212 | CHECK(mp_int_add(op1, temp, rop)); |
| 213 | |
| 214 | mp_int_clear(z: temp); |
| 215 | } |
| 216 | |
| 217 | /* gmp: mpz_divexact_ui */ |
| 218 | /* gmp: only produces correct results when d divides n */ |
| 219 | void GMPZAPI(divexact_ui)(mp_int q, mp_int n, unsigned long d) { |
| 220 | mpz_t tempz; |
| 221 | mp_int temp = &tempz; |
| 222 | CHECK(mp_int_init_uvalue(temp, d)); |
| 223 | |
| 224 | CHECK(mp_int_div(n, temp, q, NULL)); |
| 225 | |
| 226 | mp_int_clear(z: temp); |
| 227 | } |
| 228 | |
| 229 | /* gmp: mpz_mul_ui */ |
| 230 | void GMPZAPI(mul_ui)(mp_int rop, mp_int op1, unsigned long op2) { |
| 231 | mpz_t tempz; |
| 232 | mp_int temp = &tempz; |
| 233 | CHECK(mp_int_init_uvalue(temp, op2)); |
| 234 | |
| 235 | CHECK(mp_int_mul(op1, temp, rop)); |
| 236 | |
| 237 | mp_int_clear(z: temp); |
| 238 | } |
| 239 | |
| 240 | /* gmp: mpz_pow_ui */ |
| 241 | /* gmp: 0^0 = 1 */ |
| 242 | void GMPZAPI(pow_ui)(mp_int rop, mp_int base, unsigned long exp) { |
| 243 | mpz_t tempz; |
| 244 | mp_int temp = &tempz; |
| 245 | |
| 246 | /* check for 0^0 */ |
| 247 | if (exp == 0 && mp_int_compare_zero(z: base) == 0) { |
| 248 | CHECK(mp_int_set_value(rop, 1)); |
| 249 | return; |
| 250 | } |
| 251 | |
| 252 | /* rop = base^exp */ |
| 253 | CHECK(mp_int_init_uvalue(temp, exp)); |
| 254 | CHECK(mp_int_expt_full(base, temp, rop)); |
| 255 | mp_int_clear(z: temp); |
| 256 | } |
| 257 | |
| 258 | /* gmp: mpz_sub_ui */ |
| 259 | void GMPZAPI(sub_ui)(mp_int rop, mp_int op1, unsigned long op2) { |
| 260 | mpz_t tempz; |
| 261 | mp_int temp = &tempz; |
| 262 | CHECK(mp_int_init_uvalue(temp, op2)); |
| 263 | |
| 264 | CHECK(mp_int_sub(op1, temp, rop)); |
| 265 | |
| 266 | mp_int_clear(z: temp); |
| 267 | } |
| 268 | |
| 269 | /************************************************************************* |
| 270 | * |
| 271 | * Functions with different behavior in corner cases |
| 272 | * |
| 273 | *************************************************************************/ |
| 274 | |
| 275 | /* gmp: mpz_gcd */ |
| 276 | void GMPZAPI(gcd)(mp_int rop, mp_int op1, mp_int op2) { |
| 277 | int op1_is_zero = mp_int_compare_zero(z: op1) == 0; |
| 278 | int op2_is_zero = mp_int_compare_zero(z: op2) == 0; |
| 279 | |
| 280 | if (op1_is_zero && op2_is_zero) { |
| 281 | mp_int_zero(z: rop); |
| 282 | return; |
| 283 | } |
| 284 | |
| 285 | CHECK(mp_int_gcd(op1, op2, rop)); |
| 286 | } |
| 287 | |
| 288 | /* gmp: mpz_get_str */ |
| 289 | char *GMPZAPI(get_str)(char *str, int radix, mp_int op) { |
| 290 | int i, r, len; |
| 291 | |
| 292 | /* Support negative radix like gmp */ |
| 293 | r = radix; |
| 294 | if (r < 0) r = -r; |
| 295 | |
| 296 | /* Compute the length of the string needed to hold the int */ |
| 297 | len = mp_int_string_len(z: op, radix: r); |
| 298 | if (str == NULL) { |
| 299 | str = malloc(size: len); |
| 300 | } |
| 301 | |
| 302 | /* Convert to string using imath function */ |
| 303 | CHECK(mp_int_to_string(op, r, str, len)); |
| 304 | |
| 305 | /* Change case to match gmp */ |
| 306 | for (i = 0; i < len - 1; i++) { |
| 307 | if (radix < 0) { |
| 308 | str[i] = toupper(c: str[i]); |
| 309 | } else { |
| 310 | str[i] = tolower(c: str[i]); |
| 311 | } |
| 312 | } |
| 313 | return str; |
| 314 | } |
| 315 | |
| 316 | /* gmp: mpq_get_str */ |
| 317 | char *GMPQAPI(get_str)(char *str, int radix, mp_rat op) { |
| 318 | int i, r, len; |
| 319 | |
| 320 | /* Only print numerator if it is a whole number */ |
| 321 | if (mp_int_compare_value(z: mp_rat_denom_ref(r: op), v: 1) == 0) |
| 322 | return GMPZAPI(get_str)(str, radix, op: mp_rat_numer_ref(r: op)); |
| 323 | |
| 324 | /* Support negative radix like gmp */ |
| 325 | r = radix; |
| 326 | if (r < 0) r = -r; |
| 327 | |
| 328 | /* Compute the length of the string needed to hold the int */ |
| 329 | len = mp_rat_string_len(r: op, radix: r); |
| 330 | if (str == NULL) { |
| 331 | str = malloc(size: len); |
| 332 | } |
| 333 | |
| 334 | /* Convert to string using imath function */ |
| 335 | CHECK(mp_rat_to_string(op, r, str, len)); |
| 336 | |
| 337 | /* Change case to match gmp */ |
| 338 | for (i = 0; i < len; i++) { |
| 339 | if (radix < 0) { |
| 340 | str[i] = toupper(c: str[i]); |
| 341 | } else { |
| 342 | str[i] = tolower(c: str[i]); |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | return str; |
| 347 | } |
| 348 | |
| 349 | /* gmp: mpz_set_str */ |
| 350 | int GMPZAPI(set_str)(mp_int rop, char *str, int base) { |
| 351 | mp_result res = mp_int_read_string(z: rop, radix: base, str); |
| 352 | return ((res == MP_OK) ? 0 : -1); |
| 353 | } |
| 354 | |
| 355 | /* gmp: mpq_set_str */ |
| 356 | int GMPQAPI(set_str)(mp_rat rop, char *s, int base) { |
| 357 | char *slash; |
| 358 | char *str; |
| 359 | mp_result resN; |
| 360 | mp_result resD; |
| 361 | int res = 0; |
| 362 | |
| 363 | /* Copy string to temporary storage so we can modify it below */ |
| 364 | str = malloc(size: strlen(s: s) + 1); |
| 365 | strcpy(dest: str, src: s); |
| 366 | |
| 367 | /* Properly format the string as an int by terminating at the / */ |
| 368 | slash = strchr(s: str, c: '/'); |
| 369 | if (slash) *slash = '\0'; |
| 370 | |
| 371 | /* Parse numerator */ |
| 372 | resN = mp_int_read_string(z: mp_rat_numer_ref(r: rop), radix: base, str); |
| 373 | |
| 374 | /* Parse denominator if given or set to 1 if not */ |
| 375 | if (slash) { |
| 376 | resD = mp_int_read_string(z: mp_rat_denom_ref(r: rop), radix: base, str: slash + 1); |
| 377 | } else { |
| 378 | resD = mp_int_set_uvalue(z: mp_rat_denom_ref(r: rop), uvalue: 1); |
| 379 | } |
| 380 | |
| 381 | /* Return failure if either parse failed */ |
| 382 | if (resN != MP_OK || resD != MP_OK) { |
| 383 | res = -1; |
| 384 | } |
| 385 | |
| 386 | free(ptr: str); |
| 387 | return res; |
| 388 | } |
| 389 | |
| 390 | static unsigned long get_long_bits(mp_int op) { |
| 391 | /* Deal with integer that does not fit into unsigned long. We want to grab |
| 392 | * the least significant digits that will fit into the long. Read the digits |
| 393 | * into the long starting at the most significant digit that fits into a |
| 394 | * long. The long is shifted over by MP_DIGIT_BIT before each digit is added. |
| 395 | * |
| 396 | * The shift is decomposed into two steps (following the pattern used in the |
| 397 | * rest of the imath library) to accommodate architectures that don't deal |
| 398 | * well with 32-bit shifts. |
| 399 | */ |
| 400 | mp_size digits_to_copy = |
| 401 | (sizeof(unsigned long) + sizeof(mp_digit) - 1) / sizeof(mp_digit); |
| 402 | if (digits_to_copy > MP_USED(Z: op)) { |
| 403 | digits_to_copy = MP_USED(Z: op); |
| 404 | } |
| 405 | |
| 406 | mp_digit *digits = MP_DIGITS(Z: op); |
| 407 | unsigned long out = 0; |
| 408 | |
| 409 | for (int i = digits_to_copy - 1; i >= 0; i--) { |
| 410 | out <<= (MP_DIGIT_BIT / 2); |
| 411 | out <<= (MP_DIGIT_BIT / 2); |
| 412 | out |= digits[i]; |
| 413 | } |
| 414 | |
| 415 | return out; |
| 416 | } |
| 417 | |
| 418 | /* gmp: mpz_get_ui */ |
| 419 | unsigned long GMPZAPI(get_ui)(mp_int op) { |
| 420 | unsigned long out; |
| 421 | |
| 422 | /* Try a standard conversion that fits into an unsigned long */ |
| 423 | mp_result res = mp_int_to_uint(z: op, out: &out); |
| 424 | if (res == MP_OK) return out; |
| 425 | |
| 426 | /* Abort the try if we don't have a range error in the conversion. |
| 427 | * The range error indicates that the value cannot fit into a long. */ |
| 428 | CHECK(res == MP_RANGE ? MP_OK : MP_RANGE); |
| 429 | if (res != MP_RANGE) return 0; |
| 430 | |
| 431 | return get_long_bits(op); |
| 432 | } |
| 433 | |
| 434 | /* gmp: mpz_get_si */ |
| 435 | long GMPZAPI(get_si)(mp_int op) { |
| 436 | long out; |
| 437 | unsigned long uout; |
| 438 | int long_msb; |
| 439 | |
| 440 | /* Try a standard conversion that fits into a long */ |
| 441 | mp_result res = mp_int_to_int(z: op, out: &out); |
| 442 | if (res == MP_OK) return out; |
| 443 | |
| 444 | /* Abort the try if we don't have a range error in the conversion. |
| 445 | * The range error indicates that the value cannot fit into a long. */ |
| 446 | CHECK(res == MP_RANGE ? MP_OK : MP_RANGE); |
| 447 | if (res != MP_RANGE) return 0; |
| 448 | |
| 449 | /* get least significant bits into an unsigned long */ |
| 450 | uout = get_long_bits(op); |
| 451 | |
| 452 | /* clear the top bit */ |
| 453 | long_msb = (sizeof(unsigned long) * 8) - 1; |
| 454 | uout &= (~(1UL << long_msb)); |
| 455 | |
| 456 | /* convert to negative if needed based on sign of op */ |
| 457 | if (MP_SIGN(Z: op) == MP_NEG) { |
| 458 | uout = 0 - uout; |
| 459 | } |
| 460 | |
| 461 | out = (long)uout; |
| 462 | return out; |
| 463 | } |
| 464 | |
| 465 | /* gmp: mpz_lcm */ |
| 466 | void GMPZAPI(lcm)(mp_int rop, mp_int op1, mp_int op2) { |
| 467 | int op1_is_zero = mp_int_compare_zero(z: op1) == 0; |
| 468 | int op2_is_zero = mp_int_compare_zero(z: op2) == 0; |
| 469 | |
| 470 | if (op1_is_zero || op2_is_zero) { |
| 471 | mp_int_zero(z: rop); |
| 472 | return; |
| 473 | } |
| 474 | |
| 475 | CHECK(mp_int_lcm(op1, op2, rop)); |
| 476 | CHECK(mp_int_abs(rop, rop)); |
| 477 | } |
| 478 | |
| 479 | /* gmp: mpz_mul_2exp */ |
| 480 | /* gmp: allow big values for op2 when op1 == 0 */ |
| 481 | void GMPZAPI(mul_2exp)(mp_int rop, mp_int op1, unsigned long op2) { |
| 482 | if (mp_int_compare_zero(z: op1) == 0) |
| 483 | mp_int_zero(z: rop); |
| 484 | else |
| 485 | CHECK(mp_int_mul_pow2(op1, op2, rop)); |
| 486 | } |
| 487 | |
| 488 | /* |
| 489 | * Functions needing expanded functionality |
| 490 | */ |
| 491 | /* [Note]Overview of division implementation |
| 492 | |
| 493 | All division operations (N / D) compute q and r such that |
| 494 | |
| 495 | N = q * D + r, with 0 <= abs(r) < abs(d) |
| 496 | |
| 497 | The q and r values are not uniquely specified by N and D. To specify which q |
| 498 | and r values should be used, GMP implements three different rounding modes |
| 499 | for integer division: |
| 500 | |
| 501 | ceiling - round q twords +infinity, r has opposite sign as d |
| 502 | floor - round q twords -infinity, r has same sign as d |
| 503 | truncate - round q twords zero, r has same sign as n |
| 504 | |
| 505 | The imath library only supports truncate as a rounding mode. We need to |
| 506 | implement the other rounding modes in terms of truncating division. We first |
| 507 | perform the division in trucate mode and then adjust q accordingly. Once we |
| 508 | know q, we can easily compute the correct r according the the formula above |
| 509 | by computing: |
| 510 | |
| 511 | r = N - q * D |
| 512 | |
| 513 | The main task is to compute q. We can compute the correct q from a trucated |
| 514 | version as follows. |
| 515 | |
| 516 | For ceiling rounding mode, if q is less than 0 then the truncated rounding |
| 517 | mode is the same as the ceiling rounding mode. If q is greater than zero |
| 518 | then we need to round q up by one because the truncated version was rounded |
| 519 | down to zero. If q equals zero then check to see if the result of the |
| 520 | divison is positive. A positive result needs to increment q to one. |
| 521 | |
| 522 | For floor rounding mode, if q is greater than 0 then the trucated rounding |
| 523 | mode is the same as the floor rounding mode. If q is less than zero then we |
| 524 | need to round q down by one because the trucated mode rounded q up by one |
| 525 | twords zero. If q is zero then we need to check to see if the result of the |
| 526 | division is negative. A negative result needs to decrement q to negative |
| 527 | one. |
| 528 | */ |
| 529 | |
| 530 | /* gmp: mpz_cdiv_q */ |
| 531 | void GMPZAPI(cdiv_q)(mp_int q, mp_int n, mp_int d) { |
| 532 | mpz_t rz; |
| 533 | mp_int r = &rz; |
| 534 | int qsign, rsign, nsign, dsign; |
| 535 | CHECK(mp_int_init(r)); |
| 536 | |
| 537 | /* save signs before division because q can alias with n or d */ |
| 538 | nsign = mp_int_compare_zero(z: n); |
| 539 | dsign = mp_int_compare_zero(z: d); |
| 540 | |
| 541 | /* truncating division */ |
| 542 | CHECK(mp_int_div(n, d, q, r)); |
| 543 | |
| 544 | /* see: [Note]Overview of division implementation */ |
| 545 | qsign = mp_int_compare_zero(z: q); |
| 546 | rsign = mp_int_compare_zero(z: r); |
| 547 | if (qsign > 0) { /* q > 0 */ |
| 548 | if (rsign != 0) { /* r != 0 */ |
| 549 | CHECK(mp_int_add_value(q, 1, q)); |
| 550 | } |
| 551 | } else if (qsign == 0) { /* q == 0 */ |
| 552 | if (rsign != 0) { /* r != 0 */ |
| 553 | if ((nsign > 0 && dsign > 0) || (nsign < 0 && dsign < 0)) { |
| 554 | CHECK(mp_int_set_value(q, 1)); |
| 555 | } |
| 556 | } |
| 557 | } |
| 558 | mp_int_clear(z: r); |
| 559 | } |
| 560 | |
| 561 | /* gmp: mpz_fdiv_q */ |
| 562 | void GMPZAPI(fdiv_q)(mp_int q, mp_int n, mp_int d) { |
| 563 | mpz_t rz; |
| 564 | mp_int r = &rz; |
| 565 | int qsign, rsign, nsign, dsign; |
| 566 | CHECK(mp_int_init(r)); |
| 567 | |
| 568 | /* save signs before division because q can alias with n or d */ |
| 569 | nsign = mp_int_compare_zero(z: n); |
| 570 | dsign = mp_int_compare_zero(z: d); |
| 571 | |
| 572 | /* truncating division */ |
| 573 | CHECK(mp_int_div(n, d, q, r)); |
| 574 | |
| 575 | /* see: [Note]Overview of division implementation */ |
| 576 | qsign = mp_int_compare_zero(z: q); |
| 577 | rsign = mp_int_compare_zero(z: r); |
| 578 | if (qsign < 0) { /* q < 0 */ |
| 579 | if (rsign != 0) { /* r != 0 */ |
| 580 | CHECK(mp_int_sub_value(q, 1, q)); |
| 581 | } |
| 582 | } else if (qsign == 0) { /* q == 0 */ |
| 583 | if (rsign != 0) { /* r != 0 */ |
| 584 | if ((nsign < 0 && dsign > 0) || (nsign > 0 && dsign < 0)) { |
| 585 | CHECK(mp_int_set_value(q, -1)); |
| 586 | } |
| 587 | } |
| 588 | } |
| 589 | mp_int_clear(z: r); |
| 590 | } |
| 591 | |
| 592 | /* gmp: mpz_fdiv_r */ |
| 593 | void GMPZAPI(fdiv_r)(mp_int r, mp_int n, mp_int d) { |
| 594 | mpz_t qz; |
| 595 | mpz_t tempz; |
| 596 | mpz_t orig_dz; |
| 597 | mpz_t orig_nz; |
| 598 | mp_int q = &qz; |
| 599 | mp_int temp = &tempz; |
| 600 | mp_int orig_d = &orig_dz; |
| 601 | mp_int orig_n = &orig_nz; |
| 602 | CHECK(mp_int_init(q)); |
| 603 | CHECK(mp_int_init(temp)); |
| 604 | /* Make a copy of n in case n and d in case they overlap with q */ |
| 605 | CHECK(mp_int_init_copy(orig_d, d)); |
| 606 | CHECK(mp_int_init_copy(orig_n, n)); |
| 607 | |
| 608 | /* floor division */ |
| 609 | GMPZAPI(fdiv_q)(q, n, d); |
| 610 | |
| 611 | /* see: [Note]Overview of division implementation */ |
| 612 | /* n = q * d + r ==> r = n - q * d */ |
| 613 | mp_int_mul(a: q, b: orig_d, c: temp); |
| 614 | mp_int_sub(a: orig_n, b: temp, c: r); |
| 615 | |
| 616 | mp_int_clear(z: q); |
| 617 | mp_int_clear(z: temp); |
| 618 | mp_int_clear(z: orig_d); |
| 619 | mp_int_clear(z: orig_n); |
| 620 | } |
| 621 | |
| 622 | /* gmp: mpz_tdiv_q */ |
| 623 | void GMPZAPI(tdiv_q)(mp_int q, mp_int n, mp_int d) { |
| 624 | /* truncating division*/ |
| 625 | CHECK(mp_int_div(n, d, q, NULL)); |
| 626 | } |
| 627 | |
| 628 | /* gmp: mpz_fdiv_q_ui */ |
| 629 | unsigned long GMPZAPI(fdiv_q_ui)(mp_int q, mp_int n, unsigned long d) { |
| 630 | mpz_t tempz; |
| 631 | mp_int temp = &tempz; |
| 632 | mpz_t rz; |
| 633 | mp_int r = &rz; |
| 634 | mpz_t orig_nz; |
| 635 | mp_int orig_n = &orig_nz; |
| 636 | unsigned long rl; |
| 637 | CHECK(mp_int_init_uvalue(temp, d)); |
| 638 | CHECK(mp_int_init(r)); |
| 639 | /* Make a copy of n in case n and q overlap */ |
| 640 | CHECK(mp_int_init_copy(orig_n, n)); |
| 641 | |
| 642 | /* use floor division mode to compute q and r */ |
| 643 | GMPZAPI(fdiv_q)(q, n, d: temp); |
| 644 | GMPZAPI(fdiv_r)(r, n: orig_n, d: temp); |
| 645 | CHECK(mp_int_to_uint(r, &rl)); |
| 646 | |
| 647 | mp_int_clear(z: temp); |
| 648 | mp_int_clear(z: r); |
| 649 | mp_int_clear(z: orig_n); |
| 650 | |
| 651 | return rl; |
| 652 | } |
| 653 | |
| 654 | /* gmp: mpz_export */ |
| 655 | void *GMPZAPI(export)(void *rop, size_t *countp, int order, size_t size, |
| 656 | int endian, size_t nails, mp_int op) { |
| 657 | size_t i, j; |
| 658 | size_t num_used_bytes; |
| 659 | size_t num_words, num_missing_bytes; |
| 660 | ssize_t word_offset; |
| 661 | unsigned char *dst; |
| 662 | mp_digit *src; |
| 663 | int src_bits; |
| 664 | |
| 665 | /* We do not have a complete implementation. Assert to ensure our |
| 666 | * restrictions are in place. |
| 667 | */ |
| 668 | assert(nails == 0 && "Do not support non-full words" ); |
| 669 | assert(endian == 1 || endian == 0 || endian == -1); |
| 670 | assert(order == 1 || order == -1); |
| 671 | |
| 672 | /* Test for zero */ |
| 673 | if (mp_int_compare_zero(z: op) == 0) { |
| 674 | if (countp) *countp = 0; |
| 675 | return rop; |
| 676 | } |
| 677 | |
| 678 | /* Calculate how many words we need */ |
| 679 | num_used_bytes = mp_int_unsigned_len(z: op); |
| 680 | num_words = (num_used_bytes + (size - 1)) / size; /* ceil division */ |
| 681 | assert(num_used_bytes > 0); |
| 682 | |
| 683 | /* Check to see if we will have missing bytes in the last word. |
| 684 | |
| 685 | Missing bytes can only occur when the size of words we output is |
| 686 | greater than the size of words used internally by imath. The number of |
| 687 | missing bytes is the number of bytes needed to fill out the last word. If |
| 688 | this number is greater than the size of a single mp_digit, then we need to |
| 689 | pad the word with extra zeros. Otherwise, the missing bytes can be filled |
| 690 | directly from the zeros in the last digit in the number. |
| 691 | */ |
| 692 | num_missing_bytes = (size * num_words) - num_used_bytes; |
| 693 | assert(num_missing_bytes < size); |
| 694 | |
| 695 | /* Allocate space for the result if needed */ |
| 696 | if (rop == NULL) { |
| 697 | rop = malloc(size: num_words * size); |
| 698 | } |
| 699 | |
| 700 | if (endian == 0) { |
| 701 | endian = HOST_ENDIAN; |
| 702 | } |
| 703 | |
| 704 | /* Initialize dst and src pointers */ |
| 705 | dst = (unsigned char *)rop + (order >= 0 ? (num_words - 1) * size : 0) + |
| 706 | (endian >= 0 ? size - 1 : 0); |
| 707 | src = MP_DIGITS(Z: op); |
| 708 | src_bits = MP_DIGIT_BIT; |
| 709 | |
| 710 | word_offset = (endian >= 0 ? size : -size) + (order < 0 ? size : -size); |
| 711 | |
| 712 | for (i = 0; i < num_words; i++) { |
| 713 | for (j = 0; j < size && i * size + j < num_used_bytes; j++) { |
| 714 | if (src_bits == 0) { |
| 715 | ++src; |
| 716 | src_bits = MP_DIGIT_BIT; |
| 717 | } |
| 718 | *dst = (*src >> (MP_DIGIT_BIT - src_bits)) & 0xFF; |
| 719 | src_bits -= 8; |
| 720 | dst -= endian; |
| 721 | } |
| 722 | for (; j < size; j++) { |
| 723 | *dst = 0; |
| 724 | dst -= endian; |
| 725 | } |
| 726 | dst += word_offset; |
| 727 | } |
| 728 | |
| 729 | if (countp) *countp = num_words; |
| 730 | return rop; |
| 731 | } |
| 732 | |
| 733 | /* gmp: mpz_import */ |
| 734 | void GMPZAPI(import)(mp_int rop, size_t count, int order, size_t size, |
| 735 | int endian, size_t nails, const void *op) { |
| 736 | mpz_t tmpz; |
| 737 | mp_int tmp = &tmpz; |
| 738 | size_t total_size; |
| 739 | size_t num_digits; |
| 740 | ssize_t word_offset; |
| 741 | const unsigned char *src; |
| 742 | mp_digit *dst; |
| 743 | int dst_bits; |
| 744 | size_t i, j; |
| 745 | if (count == 0 || op == NULL) return; |
| 746 | |
| 747 | /* We do not have a complete implementation. Assert to ensure our |
| 748 | * restrictions are in place. */ |
| 749 | assert(nails == 0 && "Do not support non-full words" ); |
| 750 | assert(endian == 1 || endian == 0 || endian == -1); |
| 751 | assert(order == 1 || order == -1); |
| 752 | |
| 753 | if (endian == 0) { |
| 754 | endian = HOST_ENDIAN; |
| 755 | } |
| 756 | |
| 757 | /* Compute number of needed digits by ceil division */ |
| 758 | total_size = count * size; |
| 759 | num_digits = (total_size + sizeof(mp_digit) - 1) / sizeof(mp_digit); |
| 760 | |
| 761 | /* Init temporary */ |
| 762 | mp_int_init_size(z: tmp, prec: num_digits); |
| 763 | for (i = 0; i < num_digits; i++) tmp->digits[i] = 0; |
| 764 | |
| 765 | /* Copy bytes */ |
| 766 | src = (const unsigned char *)op + (order >= 0 ? (count - 1) * size : 0) + |
| 767 | (endian >= 0 ? size - 1 : 0); |
| 768 | dst = MP_DIGITS(Z: tmp); |
| 769 | dst_bits = 0; |
| 770 | |
| 771 | word_offset = (endian >= 0 ? size : -size) + (order < 0 ? size : -size); |
| 772 | |
| 773 | for (i = 0; i < count; i++) { |
| 774 | for (j = 0; j < size; j++) { |
| 775 | if (dst_bits == MP_DIGIT_BIT) { |
| 776 | ++dst; |
| 777 | dst_bits = 0; |
| 778 | } |
| 779 | *dst |= ((mp_digit)*src) << dst_bits; |
| 780 | dst_bits += 8; |
| 781 | src -= endian; |
| 782 | } |
| 783 | src += word_offset; |
| 784 | } |
| 785 | |
| 786 | tmp->used = num_digits; |
| 787 | |
| 788 | /* Remove leading zeros from number */ |
| 789 | { |
| 790 | mp_size uz_ = tmp->used; |
| 791 | mp_digit *dz_ = MP_DIGITS(Z: tmp) + uz_ - 1; |
| 792 | while (uz_ > 1 && (*dz_-- == 0)) --uz_; |
| 793 | tmp->used = uz_; |
| 794 | } |
| 795 | |
| 796 | /* Copy to destination */ |
| 797 | mp_int_copy(a: tmp, c: rop); |
| 798 | mp_int_clear(z: tmp); |
| 799 | } |
| 800 | |
| 801 | /* gmp: mpz_sizeinbase */ |
| 802 | size_t GMPZAPI(sizeinbase)(mp_int op, int base) { |
| 803 | mp_result res; |
| 804 | size_t size; |
| 805 | |
| 806 | /* If op == 0, return 1 */ |
| 807 | if (mp_int_compare_zero(z: op) == 0) return 1; |
| 808 | |
| 809 | /* Compute string length in base */ |
| 810 | res = mp_int_string_len(z: op, radix: base); |
| 811 | CHECK((res > 0) == MP_OK); |
| 812 | |
| 813 | /* Now adjust the final size by getting rid of string artifacts */ |
| 814 | size = res; |
| 815 | |
| 816 | /* subtract one for the null terminator */ |
| 817 | size -= 1; |
| 818 | |
| 819 | /* subtract one for the negative sign */ |
| 820 | if (mp_int_compare_zero(z: op) < 0) size -= 1; |
| 821 | |
| 822 | return size; |
| 823 | } |
| 824 | |