/* Check that hardware rounding doesn't make mpz_get_d_2exp return a value outside its defined range. */ static void check_round (void) { static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 }; mpz_t z; double got; long got_exp; int i, rnd_mode, old_rnd_mode; mpz_init (z); old_rnd_mode = tests_hardware_getround (); for (rnd_mode = 0; rnd_mode < 4; rnd_mode++) { tests_hardware_setround (rnd_mode); for (i = 0; i < numberof (data); i++) { mpz_set_ui (z, 1L); mpz_mul_2exp (z, z, data[i]); mpz_sub_ui (z, z, 1L); got = mpz_get_d_2exp (&got_exp, z); if (got < 0.5 || got >= 1.0) { printf ("mpz_get_d_2exp wrong on 2**%lu-1\n", data[i]); printf ("result out of range, expect 0.5 <= got < 1.0\n"); printf (" rnd_mode = %d\n", rnd_mode); printf (" data[i] = %lu\n", data[i]); mpz_trace (" z ", z); d_trace (" got ", got); printf (" got exp %ld\n", got_exp); abort(); } mpz_neg (z, z); got = mpz_get_d_2exp (&got_exp, z); if (got <= -1.0 || got > -0.5) { printf ("mpz_get_d_2exp wrong on -2**%lu-1\n", data[i]); printf ("result out of range, expect -1.0 < got <= -0.5\n"); printf (" rnd_mode = %d\n", rnd_mode); printf (" data[i] = %lu\n", data[i]); mpz_trace (" z ", z); d_trace (" got ", got); printf (" got exp %ld\n", got_exp); abort(); } } } mpz_clear (z); tests_hardware_setround (old_rnd_mode); }
static void check_onebit (void) { static const unsigned long data[] = { 1, 32, 52, 53, 54, 63, 64, 65, 128, 256, 511, 512, 513 }; mpz_t z; double got, want; long got_exp, want_exp; int i; mpz_init (z); for (i = 0; i < numberof (data); i++) { mpz_set_ui (z, 1L); mpz_mul_2exp (z, z, data[i]); want = 0.5; want_exp = data[i] + 1; got = mpz_get_d_2exp (&got_exp, z); if (got != want || got_exp != want_exp) { printf ("mpz_get_d_2exp wrong on 2**%ld\n", data[i]); mpz_trace (" z ", z); d_trace (" want ", want); d_trace (" got ", got); printf (" want exp %ld\n", want_exp); printf (" got exp %ld\n", got_exp); abort(); } mpz_set_si (z, -1L); mpz_mul_2exp (z, z, data[i]); want = -0.5; want_exp = data[i] + 1; got = mpz_get_d_2exp (&got_exp, z); if (got != want || got_exp != want_exp) { printf ("mpz_get_d_2exp wrong on -2**%ld\n", data[i]); mpz_trace (" z ", z); d_trace (" want ", want); d_trace (" got ", got); printf (" want exp %ld\n", want_exp); printf (" got exp %ld\n", got_exp); abort(); } } mpz_clear (z); }
/* rslt is always integral due to ceiling operation */ void mpz_logbase2cl (sli_t * rslt, mpz_t n) { if (mpz_get_d_2exp (rslt, n) == 0.5) { --(*rslt); } }
double fmpz_dlog(const fmpz_t x) { if (!COEFF_IS_MPZ(*x)) { return log(*x); } else { double s; slong e; #if defined(__MPIR_VERSION) s = mpz_get_d_2exp(&e, COEFF_TO_PTR(*x)); #else s = mpz_get_d_2exp((long *) &e, COEFF_TO_PTR(*x)); #endif return log(s) + e * 0.69314718055994530942; } }
static void check_rand (void) { gmp_randstate_ptr rands = RANDS; int i; mpz_t z; double got; long got_exp; unsigned long bits; mpz_init (z); for (i = 0; i < 200; i++) { bits = gmp_urandomm_ui (rands, 512L); mpz_urandomb (z, rands, bits); got = mpz_get_d_2exp (&got_exp, z); if (mpz_sgn (z) == 0) continue; bits = mpz_sizeinbase (z, 2); if (got < 0.5 || got >= 1.0) { printf ("mpz_get_d_2exp out of range, expect 0.5 <= got < 1.0\n"); mpz_trace (" z ", z); d_trace (" got ", got); printf (" got exp %ld\n", got_exp); abort(); } /* FIXME: If mpz_get_d_2exp rounds upwards we might have got_exp == bits+1, so leave this test disabled until we decide if that's what should happen, or not. */ #if 0 if (got_exp != bits) { printf ("mpz_get_d_2exp wrong exponent\n", i); mpz_trace (" z ", z); d_trace (" bits ", bits); d_trace (" got ", got); printf (" got exp %ld\n", got_exp); abort(); } #endif } mpz_clear (z); }
/* Convert bignum to a `double`, truncating if necessary * (i.e. rounding towards zero). * * sign of mp_size_t argument controls sign of converted double */ HsDouble integer_gmp_mpn_get_d (const mp_limb_t sp[], const mp_size_t sn, const HsInt exponent) { if (mp_limb_zero_p(sp, sn)) return 0.0; const mpz_t mpz = CONST_MPZ_INIT(sp, sn); if (!exponent) return mpz_get_d(mpz); long e = 0; double d = mpz_get_d_2exp (&e, mpz); // TODO: over/underflow handling? return ldexp(d, e+exponent); }