perfsqr.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:8k
源码类别:

数学计算

开发平台:

Unix_Linux

  1. /* mpn_perfect_square_p(u,usize) -- Return non-zero if U is a perfect square,
  2.    zero otherwise.
  3. Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2002, 2005 Free Software
  4. Foundation, Inc.
  5. This file is part of the GNU MP Library.
  6. The GNU MP Library is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU Lesser General Public License as published by
  8. the Free Software Foundation; either version 3 of the License, or (at your
  9. option) any later version.
  10. The GNU MP Library is distributed in the hope that it will be useful, but
  11. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  13. License for more details.
  14. You should have received a copy of the GNU Lesser General Public License
  15. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  16. #include <stdio.h> /* for NULL */
  17. #include "gmp.h"
  18. #include "gmp-impl.h"
  19. #include "longlong.h"
  20. #include "perfsqr.h"
  21. /* change this to "#define TRACE(x) x" for diagnostics */
  22. #define TRACE(x)
  23. /* PERFSQR_MOD_* detects non-squares using residue tests.
  24.    A macro PERFSQR_MOD_TEST is setup by gen-psqr.c in perfsqr.h.  It takes
  25.    {up,usize} modulo a selected modulus to get a remainder r.  For 32-bit or
  26.    64-bit limbs this modulus will be 2^24-1 or 2^48-1 using PERFSQR_MOD_34,
  27.    or for other limb or nail sizes a PERFSQR_PP is chosen and PERFSQR_MOD_PP
  28.    used.  PERFSQR_PP_NORM and PERFSQR_PP_INVERTED are pre-calculated in this
  29.    case too.
  30.    PERFSQR_MOD_TEST then makes various calls to PERFSQR_MOD_1 or
  31.    PERFSQR_MOD_2 with divisors d which are factors of the modulus, and table
  32.    data indicating residues and non-residues modulo those divisors.  The
  33.    table data is in 1 or 2 limbs worth of bits respectively, per the size of
  34.    each d.
  35.    A "modexact" style remainder is taken to reduce r modulo d.
  36.    PERFSQR_MOD_IDX implements this, producing an index "idx" for use with
  37.    the table data.  Notice there's just one multiplication by a constant
  38.    "inv", for each d.
  39.    The modexact doesn't produce a true r%d remainder, instead idx satisfies
  40.    "-(idx<<PERFSQR_MOD_BITS) == r mod d".  Because d is odd, this factor
  41.    -2^PERFSQR_MOD_BITS is a one-to-one mapping between r and idx, and is
  42.    accounted for by having the table data suitably permuted.
  43.    The remainder r fits within PERFSQR_MOD_BITS which is less than a limb.
  44.    In fact the GMP_LIMB_BITS - PERFSQR_MOD_BITS spare bits are enough to fit
  45.    each divisor d meaning the modexact multiply can take place entirely
  46.    within one limb, giving the compiler the chance to optimize it, in a way
  47.    that say umul_ppmm would not give.
  48.    There's no need for the divisors d to be prime, in fact gen-psqr.c makes
  49.    a deliberate effort to combine factors so as to reduce the number of
  50.    separate tests done on r.  But such combining is limited to d <=
  51.    2*GMP_LIMB_BITS so that the table data fits in at most 2 limbs.
  52.    Alternatives:
  53.    It'd be possible to use bigger divisors d, and more than 2 limbs of table
  54.    data, but this doesn't look like it would be of much help to the prime
  55.    factors in the usual moduli 2^24-1 or 2^48-1.
  56.    The moduli 2^24-1 or 2^48-1 are nothing particularly special, they're
  57.    just easy to calculate (see mpn_mod_34lsub1) and have a nice set of prime
  58.    factors.  2^32-1 and 2^64-1 would be equally easy to calculate, but have
  59.    fewer prime factors.
  60.    The nails case usually ends up using mpn_mod_1, which is a lot slower
  61.    than mpn_mod_34lsub1.  Perhaps other such special moduli could be found
  62.    for the nails case.  Two-term things like 2^30-2^15-1 might be
  63.    candidates.  Or at worst some on-the-fly de-nailing would allow the plain
  64.    2^24-1 to be used.  Currently nails are too preliminary to be worried
  65.    about.
  66. */
  67. #define PERFSQR_MOD_MASK       ((CNST_LIMB(1) << PERFSQR_MOD_BITS) - 1)
  68. #define MOD34_BITS  (GMP_NUMB_BITS / 4 * 3)
  69. #define MOD34_MASK  ((CNST_LIMB(1) << MOD34_BITS) - 1)
  70. #define PERFSQR_MOD_34(r, up, usize)
  71.   do {
  72.     (r) = mpn_mod_34lsub1 (up, usize);
  73.     (r) = ((r) & MOD34_MASK) + ((r) >> MOD34_BITS);
  74.   } while (0)
  75. /* FIXME: The %= here isn't good, and might destroy any savings from keeping
  76.    the PERFSQR_MOD_IDX stuff within a limb (rather than needing umul_ppmm).
  77.    Maybe a new sort of mpn_preinv_mod_1 could accept an unnormalized divisor
  78.    and a shift count, like mpn_preinv_divrem_1.  But mod_34lsub1 is our
  79.    normal case, so lets not worry too much about mod_1.  */
  80. #define PERFSQR_MOD_PP(r, up, usize)
  81.   do {
  82.     if (BELOW_THRESHOLD (usize, PREINV_MOD_1_TO_MOD_1_THRESHOLD))
  83.       {
  84. (r) = mpn_preinv_mod_1 (up, usize, PERFSQR_PP_NORM,
  85. PERFSQR_PP_INVERTED);
  86. (r) %= PERFSQR_PP;
  87.       }
  88.     else
  89.       {
  90. (r) = mpn_mod_1 (up, usize, PERFSQR_PP);
  91.       }
  92.   } while (0)
  93. #define PERFSQR_MOD_IDX(idx, r, d, inv)
  94.   do {
  95.     mp_limb_t  q;
  96.     ASSERT ((r) <= PERFSQR_MOD_MASK);
  97.     ASSERT ((((inv) * (d)) & PERFSQR_MOD_MASK) == 1);
  98.     ASSERT (MP_LIMB_T_MAX / (d) >= PERFSQR_MOD_MASK);
  99.     q = ((r) * (inv)) & PERFSQR_MOD_MASK;
  100.     ASSERT (r == ((q * (d)) & PERFSQR_MOD_MASK));
  101.     (idx) = (q * (d)) >> PERFSQR_MOD_BITS;
  102.   } while (0)
  103. #define PERFSQR_MOD_1(r, d, inv, mask)
  104.   do {
  105.     unsigned   idx;
  106.     ASSERT ((d) <= GMP_LIMB_BITS);
  107.     PERFSQR_MOD_IDX(idx, r, d, inv);
  108.     TRACE (printf ("  PERFSQR_MOD_1 d=%u r=%lu idx=%un",
  109.    d, r%d, idx));
  110.     if ((((mask) >> idx) & 1) == 0)
  111.       {
  112. TRACE (printf ("  non-squaren"));
  113. return 0;
  114.       }
  115.   } while (0)
  116. /* The expression "(int) idx - GMP_LIMB_BITS < 0" lets the compiler use the
  117.    sign bit from "idx-GMP_LIMB_BITS", which might help avoid a branch. */
  118. #define PERFSQR_MOD_2(r, d, inv, mhi, mlo)
  119.   do {
  120.     mp_limb_t  m;
  121.     unsigned   idx;
  122.     ASSERT ((d) <= 2*GMP_LIMB_BITS);
  123.     PERFSQR_MOD_IDX (idx, r, d, inv);
  124.     TRACE (printf ("  PERFSQR_MOD_2 d=%u r=%lu idx=%un",
  125.    d, r%d, idx));
  126.     m = ((int) idx - GMP_LIMB_BITS < 0 ? (mlo) : (mhi));
  127.     idx %= GMP_LIMB_BITS;
  128.     if (((m >> idx) & 1) == 0)
  129.       {
  130. TRACE (printf ("  non-squaren"));
  131. return 0;
  132.       }
  133.   } while (0)
  134. int
  135. mpn_perfect_square_p (mp_srcptr up, mp_size_t usize)
  136. {
  137.   ASSERT (usize >= 1);
  138.   TRACE (gmp_printf ("mpn_perfect_square_p %Ndn", up, usize));
  139.   /* The first test excludes 212/256 (82.8%) of the perfect square candidates
  140.      in O(1) time.  */
  141.   {
  142.     unsigned  idx = up[0] % 0x100;
  143.     if (((sq_res_0x100[idx / GMP_LIMB_BITS]
  144.   >> (idx % GMP_LIMB_BITS)) & 1) == 0)
  145.       return 0;
  146.   }
  147. #if 0
  148.   /* Check that we have even multiplicity of 2, and then check that the rest is
  149.      a possible perfect square.  Leave disabled until we can determine this
  150.      really is an improvement.  It it is, it could completely replace the
  151.      simple probe above, since this should through out more non-squares, but at
  152.      the expense of somewhat more cycles.  */
  153.   {
  154.     mp_limb_t lo;
  155.     int cnt;
  156.     lo = up[0];
  157.     while (lo == 0)
  158.       up++, lo = up[0], usize--;
  159.     count_trailing_zeros (cnt, lo);
  160.     if ((cnt & 1) != 0)
  161.       return 0; /* return of not even multiplicity of 2 */
  162.     lo >>= cnt; /* shift down to align lowest non-zero bit */
  163.     lo >>= 1; /* shift away lowest non-zero bit */
  164.     if ((lo & 3) != 0)
  165.       return 0;
  166.   }
  167. #endif
  168.   /* The second test uses mpn_mod_34lsub1 or mpn_mod_1 to detect non-squares
  169.      according to their residues modulo small primes (or powers of
  170.      primes).  See perfsqr.h.  */
  171.   PERFSQR_MOD_TEST (up, usize);
  172.   /* For the third and last test, we finally compute the square root,
  173.      to make sure we've really got a perfect square.  */
  174.   {
  175.     mp_ptr root_ptr;
  176.     int res;
  177.     TMP_DECL;
  178.     TMP_MARK;
  179.     root_ptr = TMP_ALLOC_LIMBS ((usize + 1) / 2);
  180.     /* Iff mpn_sqrtrem returns zero, the square is perfect.  */
  181.     res = ! mpn_sqrtrem (root_ptr, NULL, up, usize);
  182.     TMP_FREE;
  183.     return res;
  184.   }
  185. }