📄 sqrtrem.c
字号:
/* mpn_sqrtrem -- square root and remainder *//*Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.This file is part of the GNU MP Library.The GNU MP Library is free software; you can redistribute it and/or modifyit under the terms of the GNU Lesser General Public License as published bythe Free Software Foundation; either version 2.1 of the License, or (at youroption) any later version.The GNU MP Library is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITYor FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General PublicLicense for more details.You should have received a copy of the GNU Lesser General Public Licensealong with the GNU MP Library; see the file COPYING.LIB. If not, write tothe Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,MA 02111-1307, USA.*//* Contributed by Paul Zimmermann. See "Karatsuba Square Root", reference in gmp.texi. */#include <stdio.h>#include <stdlib.h>#include "gmp.h"#include "gmp-impl.h"#include "longlong.h"/* Square roots table. Generated by the following program:#include "gmp.h"main(){mpz_t x;int i;mpz_init(x);for(i=64;i<256;i++){mpz_set_ui(x,256*i);mpz_sqrt(x,x);mpz_out_str(0,10,x);printf(",");if(i%16==15)printf("\n");}}*/static const unsigned char approx_tab[192] = { 128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142, 143,144,144,145,146,147,148,149,150,150,151,152,153,154,155,155, 156,157,158,159,160,160,161,162,163,163,164,165,166,167,167,168, 169,170,170,171,172,173,173,174,175,176,176,177,178,178,179,180, 181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,191, 192,192,193,193,194,195,195,196,197,197,198,199,199,200,201,201, 202,203,203,204,204,205,206,206,207,208,208,209,209,210,211,211, 212,212,213,214,214,215,215,216,217,217,218,218,219,219,220,221, 221,222,222,223,224,224,225,225,226,226,227,227,228,229,229,230, 230,231,231,232,232,233,234,234,235,235,236,236,237,237,238,238, 239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247, 247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255 };#define HALF_NAIL (GMP_NAIL_BITS / 2)/* same as mpn_sqrtrem, but for size=1 and {np, 1} normalized */static mp_size_tmpn_sqrtrem1 (mp_ptr sp, mp_ptr rp, mp_srcptr np){ mp_limb_t np0, s, r, q, u; int prec; ASSERT (np[0] >= GMP_NUMB_HIGHBIT / 2); ASSERT (GMP_LIMB_BITS >= 16); /* first compute a 8-bit approximation from the high 8-bits of np[0] */ np0 = np[0] << GMP_NAIL_BITS; q = np0 >> (GMP_LIMB_BITS - 8); /* 2^6 = 64 <= q < 256 = 2^8 */ s = approx_tab[q - 64]; /* 128 <= s < 255 */ r = (np0 >> (GMP_LIMB_BITS - 16)) - s * s; /* r <= 2*s */ if (r > 2 * s) { r -= 2 * s + 1; s++; } prec = 8; np0 <<= 2 * prec; while (2 * prec < GMP_LIMB_BITS) { /* invariant: s has prec bits, and r <= 2*s */ r = (r << prec) + (np0 >> (GMP_LIMB_BITS - prec)); np0 <<= prec; u = 2 * s; q = r / u; u = r - q * u; s = (s << prec) + q; u = (u << prec) + (np0 >> (GMP_LIMB_BITS - prec)); q = q * q; r = u - q; if (u < q) { r += 2 * s - 1; s --; } np0 <<= prec; prec = 2 * prec; } ASSERT (2 * prec == GMP_LIMB_BITS); /* GMP_LIMB_BITS must be a power of 2 */ /* normalize back, assuming GMP_NAIL_BITS is even */ ASSERT (GMP_NAIL_BITS % 2 == 0); sp[0] = s >> HALF_NAIL; u = s - (sp[0] << HALF_NAIL); /* s mod 2^HALF_NAIL */ r += u * ((sp[0] << (HALF_NAIL + 1)) + u); r = r >> GMP_NAIL_BITS; if (rp != NULL) rp[0] = r; return r != 0 ? 1 : 0;}#define Prec (GMP_NUMB_BITS >> 1)/* same as mpn_sqrtrem, but for size=2 and {np, 2} normalized return cc such that {np, 2} = sp[0]^2 + cc*2^GMP_NUMB_BITS + rp[0] */static mp_limb_tmpn_sqrtrem2 (mp_ptr sp, mp_ptr rp, mp_srcptr np){ mp_limb_t qhl, q, u, np0; int cc; ASSERT (np[1] >= GMP_NUMB_HIGHBIT / 2); np0 = np[0]; mpn_sqrtrem1 (sp, rp, np + 1); qhl = 0; while (rp[0] >= sp[0]) { qhl++; rp[0] -= sp[0]; } /* now rp[0] < sp[0] < 2^Prec */ rp[0] = (rp[0] << Prec) + (np0 >> Prec); u = 2 * sp[0]; q = rp[0] / u; u = rp[0] - q * u; q += (qhl & 1) << (Prec - 1); qhl >>= 1; /* if qhl=1, necessary q=0 as qhl*2^Prec + q <= 2^Prec */ /* now we have (initial rp[0])<<Prec + np0>>Prec = (qhl<<Prec + q) * (2sp[0]) + u */ sp[0] = ((sp[0] + qhl) << Prec) + q; cc = u >> Prec; rp[0] = ((u << Prec) & GMP_NUMB_MASK) + (np0 & (((mp_limb_t) 1 << Prec) - 1)); /* subtract q * q or qhl*2^(2*Prec) from rp */ cc -= mpn_sub_1 (rp, rp, 1, q * q) + qhl; /* now subtract 2*q*2^Prec + 2^(2*Prec) if qhl is set */ if (cc < 0) { cc += sp[0] != 0 ? mpn_add_1 (rp, rp, 1, sp[0]) : 1; cc += mpn_add_1 (rp, rp, 1, --sp[0]); } return cc;}/* writes in {sp, n} the square root (rounded towards zero) of {np, 2n}, and in {np, n} the low n limbs of the remainder, returns the high limb of the remainder (which is 0 or 1). Assumes {np, 2n} is normalized, i.e. np[2n-1] >= B/4 where B=2^GMP_NUMB_BITS. */static mp_limb_tmpn_dc_sqrtrem (mp_ptr sp, mp_ptr np, mp_size_t n){ mp_limb_t q; /* carry out of {sp, n} */ int c, b; /* carry out of remainder */ mp_size_t l, h; ASSERT (np[2 * n - 1] >= GMP_NUMB_HIGHBIT / 2); if (n == 1) c = mpn_sqrtrem2 (sp, np, np); else { l = n / 2; h = n - l; q = mpn_dc_sqrtrem (sp + l, np + 2 * l, h); if (q != 0) mpn_sub_n (np + 2 * l, np + 2 * l, sp + l, h); q += mpn_divrem (sp, 0, np + l, n, sp + l, h); c = sp[0] & 1; mpn_rshift (sp, sp, l, 1); sp[l - 1] |= (q << (GMP_NUMB_BITS - 1)) & GMP_NUMB_MASK; q >>= 1; if (c != 0) c = mpn_add_n (np + l, np + l, sp + l, h); mpn_sqr_n (np + n, sp, l); b = q + mpn_sub_n (np, np, np + n, 2 * l); c -= (l == h) ? b : mpn_sub_1 (np + 2 * l, np + 2 * l, 1, b); q = mpn_add_1 (sp + l, sp + l, h, q); if (c < 0) { c += mpn_addmul_1 (np, sp, n, 2) + 2 * q; c -= mpn_sub_1 (np, np, n, 1); q -= mpn_sub_1 (sp, sp, n, 1); } } return c;}mp_size_tmpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr np, mp_size_t nn){ mp_limb_t *tp, s0[1], cc, high, rl; int c; mp_size_t rn, tn; TMP_DECL (marker); ASSERT (nn >= 0); /* If OP is zero, both results are zero. */ if (nn == 0) return 0; ASSERT (np[nn - 1] != 0); ASSERT (rp == NULL || MPN_SAME_OR_SEPARATE_P (np, rp, nn)); ASSERT (rp == NULL || ! MPN_OVERLAP_P (sp, (nn + 1) / 2, rp, nn)); ASSERT (! MPN_OVERLAP_P (sp, (nn + 1) / 2, np, nn)); high = np[nn - 1]; if (nn == 1 && (high & GMP_NUMB_HIGHBIT)) return mpn_sqrtrem1 (sp, rp, np); count_leading_zeros (c, high); c -= GMP_NAIL_BITS; c = c / 2; /* we have to shift left by 2c bits to normalize {np, nn} */ tn = (nn + 1) / 2; /* 2*tn is the smallest even integer >= nn */ TMP_MARK (marker); if (nn % 2 != 0 || c > 0) { tp = TMP_ALLOC_LIMBS (2 * tn); tp[0] = 0; /* needed only when 2*tn > nn, but saves a test */ if (c != 0) mpn_lshift (tp + 2 * tn - nn, np, nn, 2 * c); else MPN_COPY (tp + 2 * tn - nn, np, nn); rl = mpn_dc_sqrtrem (sp, tp, tn); /* We have 2^(2k)*N = S^2 + R where k = c + (2tn-nn)*GMP_NUMB_BITS/2, thus 2^(2k)*N = (S-s0)^2 + 2*S*s0 - s0^2 + R where s0=S mod 2^k */ c += (nn % 2) * GMP_NUMB_BITS / 2; /* c now represents k */ s0[0] = sp[0] & (((mp_limb_t) 1 << c) - 1); /* S mod 2^k */ rl += mpn_addmul_1 (tp, sp, tn, 2 * s0[0]); /* R = R + 2*s0*S */ cc = mpn_submul_1 (tp, s0, 1, s0[0]); rl -= (tn > 1) ? mpn_sub_1 (tp + 1, tp + 1, tn - 1, cc) : cc; mpn_rshift (sp, sp, tn, c); tp[tn] = rl; if (rp == NULL) rp = tp; c = c << 1; if (c < GMP_NUMB_BITS) tn++; else { tp++; c -= GMP_NUMB_BITS; } if (c != 0) mpn_rshift (rp, tp, tn, c); else MPN_COPY_INCR (rp, tp, tn); rn = tn; } else { if (rp == NULL) rp = TMP_ALLOC_LIMBS (nn); if (rp != np) MPN_COPY (rp, np, nn); rn = tn + (rp[tn] = mpn_dc_sqrtrem (sp, rp, tn)); } MPN_NORMALIZE (rp, rn); TMP_FREE (marker); return rn;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -