/* r = sqrt(x) */ void my_sqrt_ui(mpf_t r, unsigned long x) { unsigned long prec, bits, prec0; prec0 = mpf_get_prec(r); if (prec0<=DOUBLE_PREC) { mpf_set_d(r, sqrt(x)); return; } bits = 0; for (prec=prec0; prec>DOUBLE_PREC;) { int bit = prec&1; prec = (prec+bit)/2; bits = bits*2+bit; } mpf_set_prec_raw(t1, DOUBLE_PREC); mpf_set_d(t1, 1/sqrt(x)); while (prec<prec0) { prec *=2; if (prec<prec0) { /* t1 = t1+t1*(1-x*t1*t1)/2; */ mpf_set_prec_raw(t2, prec); mpf_mul(t2, t1, t1); /* half x half -> full */ mpf_mul_ui(t2, t2, x); mpf_ui_sub(t2, 1, t2); mpf_set_prec_raw(t2, prec/2); mpf_div_2exp(t2, t2, 1); mpf_mul(t2, t2, t1); /* half x half -> half */ mpf_set_prec_raw(t1, prec); mpf_add(t1, t1, t2); } else { break; } prec -= (bits&1); bits /=2; } /* t2=x*t1, t1 = t2+t1*(x-t2*t2)/2; */ mpf_set_prec_raw(t2, prec0/2); mpf_mul_ui(t2, t1, x); mpf_mul(r, t2, t2); /* half x half -> full */ mpf_ui_sub(r, x, r); mpf_mul(t1, t1, r); /* half x half -> half */ mpf_div_2exp(t1, t1, 1); mpf_add(r, t1, t2); }
void my_out_str_raw(FILE *fp, unsigned long digits, mpf_t f, unsigned long offset) { unsigned long d; if (digits <= LINE_SIZE*NUM_BLOCKS) { unsigned long cursor = offset % LINE_SIZE; for (d = 0; d < digits; ) { mpf_set_prec_raw(f, (int)((digits-d)*BITS_PER_DIGIT+1)); mpf_mul_ui(f, f, UNIT_MOD); unsigned long i = mpf_get_ui(f); mpf_sub_ui(f, f, i); utoa(i, UNIT_SIZE); *out_ptr++ = ' '; d += UNIT_SIZE; cursor += UNIT_SIZE; if (cursor == LINE_SIZE) { cursor = 0; *out_ptr++ = ':'; *out_ptr++ = ' '; utoa(offset + d, 0); *out_ptr++ = '\n'; if ((offset + d) % (LINE_SIZE*10) == 0) flush_out(fp); } } } else { mpf_t block, mod; unsigned long num_units = (digits + UNIT_SIZE-1)/UNIT_SIZE; unsigned long block_size = (num_units + NUM_BLOCKS-1)/NUM_BLOCKS*UNIT_SIZE; mpf_set_default_prec((int)(block_size*BITS_PER_DIGIT+1)); mpf_init(block); mpf_init_set_ui(mod, 10); mpf_pow_ui(mod, mod, block_size); for (d = 0; d < digits; d += block_size) { unsigned long size = block_size < digits - d ? block_size : digits - d; mpf_set_prec_raw(block, (int)(size*BITS_PER_DIGIT+1)); mpf_set(block, f); my_out_str_raw(fp, size, block, offset+d); if (block_size < digits - d) { mpf_set_prec_raw(f, (int)((digits-d)*BITS_PER_DIGIT+1)); mpf_mul(f, f, mod); mpf_floor(trunk, f); mpf_sub(f, f, trunk); } } mpf_clear(block); mpf_clear(mod); } }
// r = y/x WARNING: r cannot be the same as y. void my_div(mpf_t r, mpf_t y, mpf_t x) { unsigned long prec, bits, prec0; prec0 = mpf_get_prec(r); if (prec0<=DOUBLE_PREC) { mpf_set_d(r, mpf_get_d(y)/mpf_get_d(x)); return; } bits = 0; for (prec=prec0; prec>DOUBLE_PREC;) { int bit = prec&1; prec = (prec+bit)/2; bits = bits*2+bit; } mpf_set_prec_raw(t1, DOUBLE_PREC); mpf_ui_div(t1, 1, x); while (prec<prec0) { prec *=2; if (prec<prec0) { /* t1 = t1+t1*(1-x*t1); */ mpf_set_prec_raw(t2, prec); mpf_mul(t2, x, t1); // full x half -> full mpf_ui_sub(t2, 1, t2); mpf_set_prec_raw(t2, prec/2); mpf_mul(t2, t2, t1); // half x half -> half mpf_set_prec_raw(t1, prec); mpf_add(t1, t1, t2); } else { prec = prec0; /* t2=y*t1, t1 = t2+t1*(y-x*t2); */ mpf_set_prec_raw(t2, prec/2); mpf_mul(t2, t1, y); // half x half -> half mpf_mul(r, x, t2); // full x half -> full mpf_sub(r, y, r); mpf_mul(t1, t1, r); // half x half -> half mpf_add(r, t1, t2); break; } prec -= (bits&1); bits /=2; } }
void check_reuse (void) { /* Try mpf_set(f,f) when f is bigger than prec. In the past this had resulted in an MPN_COPY with invalid operand overlap. */ mpf_t f; mp_size_t limbs = 20; unsigned long bits = limbs * GMP_NUMB_BITS; mpf_init2 (f, bits); refmpf_fill (f, limbs, GMP_NUMB_MAX); mpf_set_prec_raw (f, bits / 2); mpf_set (f, f); MPF_CHECK_FORMAT (f); mpf_set_prec_raw (f, bits); mpf_clear (f); }
void check_rand (void) { unsigned long min_prec = __GMPF_BITS_TO_PREC (1); gmp_randstate_t rands; mpf_t got, u; unsigned long prec, v; int i; /* The nails code in mpf_mul_ui currently isn't exact, so suppress these tests for now. */ if (BITS_PER_UI > GMP_NUMB_BITS) return; mpf_init (got); mpf_init (u); gmp_randinit_default(rands); for (i = 0; i < 200; i++) { /* got precision */ prec = min_prec + gmp_urandomm_ui (rands, 15L); refmpf_set_prec_limbs (got, prec); /* u precision */ prec = min_prec + gmp_urandomm_ui (rands, 15L); refmpf_set_prec_limbs (u, prec); /* u, possibly negative */ mpf_rrandomb (u, rands, PREC(u), (mp_exp_t) 20); if (gmp_urandomb_ui (rands, 1L)) mpf_neg (u, u); /* v, 0 to BITS_PER_ULONG bits (inclusive) */ prec = gmp_urandomm_ui (rands, BITS_PER_ULONG+1); v = gmp_urandomb_ui (rands, prec); if ((i % 2) == 0) { /* separate */ mpf_mul_ui (got, u, v); check_one ("separate", got, u, v); } else { /* overlap */ prec = refmpf_set_overlap (got, u); mpf_mul_ui (got, got, v); check_one ("overlap src==dst", got, u, v); mpf_set_prec_raw (got, prec); } } mpf_clear (got); mpf_clear (u); gmp_randclear(rands); }
// r = sqrt(x) void my_sqrt(mpf_t r, mpf_t x) { unsigned prec, bits, prec0; prec0 = mpf_get_prec(r); if (prec0 <= DOUBLE_PREC) { mpf_set_d(r, sqrt(mpf_get_d(x))); return; } bits = 0; for (prec = prec0; prec > DOUBLE_PREC;) { int bit = prec & 1; prec = (prec + bit) / 2; bits = bits * 2 + bit; } mpf_set_prec_raw(t1, DOUBLE_PREC); mpf_set_d(t1, 1 / sqrt(mpf_get_d(x))); while (prec < prec0) { prec *= 2; /*printf("prec=%d, prec0=%d\n", prec, prec0); */ if (prec < prec0) { /* t1 = t1+t1*(1-x*t1*t1)/2; */ mpf_set_prec_raw(t2, prec); mpf_mul(t2, t1, t1); mpf_set_prec_raw(x, prec/2); mpf_mul(t2, t2, x); mpf_ui_sub(t2, 1, t2); mpf_set_prec_raw(t2, prec/2); mpf_div_2exp(t2, t2, 1); mpf_mul(t2, t2, t1); mpf_set_prec_raw(t1, prec); mpf_add(t1, t1, t2); } else { prec = prec0; /* t2=x*t1, t1 = t2+t1*(x-t2*t2)/2; */ mpf_set_prec_raw(t2, prec/2); mpf_set_prec_raw(x, prec/2); mpf_mul(t2, t1, x); mpf_mul(r, t2, t2); mpf_set_prec_raw(x, prec); mpf_sub(r, x, r); mpf_mul(t1, t1, r); mpf_div_2exp(t1, t1, 1); mpf_add(r, t1, t2); break; } prec -= (bits & 1); bits /= 2; } }
void my_divexact(mpz_t r, mpz_t y, mpz_t x) { unsigned long prec = mpz_sizeinbase(y, 2); unsigned long prec2 = mpz_sizeinbase(x, 2); if (prec >= div_threshold) { mpf_set_prec_raw(d1, prec); mpf_set_prec_raw(d2, prec); mpf_set_z(d1, y); mpf_set_z(d2, x); mpf_div_2exp(d1, d1, prec); mpf_div_2exp(d2, d2, prec2); my_div(d2, d1, d2); mpf_mul_2exp(d2, d2, prec-prec2); mpf_set_d(d1, 0.5); mpf_add(d2, d2, d1); mpz_set_f(y, d2); } else { mpz_divexact(y, y, x); //mpz_tdiv_q(y, y, x); } }
void check_rand (void) { unsigned long min_prec = __GMPF_BITS_TO_PREC (1); gmp_randstate_ptr rands = RANDS; unsigned long prec; mpf_t got, u, v; int i; mpf_init (got); mpf_init (u); mpf_init (v); /* separate */ for (i = 0; i < 100; i++) { /* got precision */ prec = min_prec + gmp_urandomm_ui (rands, 15L); refmpf_set_prec_limbs (got, prec); /* u */ prec = min_prec + gmp_urandomm_ui (rands, 15L); refmpf_set_prec_limbs (u, prec); do { mpf_random2 (u, PREC(u), (mp_exp_t) 20); } while (SIZ(u) == 0); if (gmp_urandomb_ui (rands, 1L)) mpf_neg (u, u); /* v */ prec = min_prec + gmp_urandomm_ui (rands, 15L); refmpf_set_prec_limbs (v, prec); do { mpf_random2 (v, PREC(v), (mp_exp_t) 20); } while (SIZ(v) == 0); if (gmp_urandomb_ui (rands, 1L)) mpf_neg (v, v); switch (i % 3) { case 0: mpf_div (got, u, v); check_one ("separate", got, u, v); break; case 1: prec = refmpf_set_overlap (got, u); mpf_div (got, got, v); check_one ("dst == u", got, u, v); mpf_set_prec_raw (got, prec); break; case 2: prec = refmpf_set_overlap (got, v); mpf_div (got, u, got); check_one ("dst == v", got, u, v); mpf_set_prec_raw (got, prec); break; } } mpf_clear (got); mpf_clear (u); mpf_clear (v); }