Home | History | Annotate | Line # | Download | only in tests
t-sqrt.c revision 1.1.1.2
      1      1.1  mrg /*
      2      1.1  mrg 
      3  1.1.1.2  mrg Copyright 2012, 2014, Free Software Foundation, Inc.
      4      1.1  mrg 
      5      1.1  mrg This file is part of the GNU MP Library test suite.
      6      1.1  mrg 
      7      1.1  mrg The GNU MP Library test suite is free software; you can redistribute it
      8      1.1  mrg and/or modify it under the terms of the GNU General Public License as
      9      1.1  mrg published by the Free Software Foundation; either version 3 of the License,
     10      1.1  mrg or (at your option) any later version.
     11      1.1  mrg 
     12      1.1  mrg The GNU MP Library test suite is distributed in the hope that it will be
     13      1.1  mrg useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
     15      1.1  mrg Public License for more details.
     16      1.1  mrg 
     17      1.1  mrg You should have received a copy of the GNU General Public License along with
     18  1.1.1.2  mrg the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
     19      1.1  mrg 
     20      1.1  mrg #include <limits.h>
     21      1.1  mrg #include <stdlib.h>
     22      1.1  mrg #include <stdio.h>
     23      1.1  mrg 
     24      1.1  mrg #include "testutils.h"
     25      1.1  mrg 
     26      1.1  mrg #define MAXBITS 400
     27  1.1.1.2  mrg #define COUNT 9000
     28      1.1  mrg 
     29      1.1  mrg /* Called when s is supposed to be floor(sqrt(u)), and r = u - s^2 */
     30      1.1  mrg static int
     31      1.1  mrg sqrtrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r)
     32      1.1  mrg {
     33      1.1  mrg   mpz_t t;
     34      1.1  mrg 
     35      1.1  mrg   mpz_init (t);
     36      1.1  mrg   mpz_mul (t, s, s);
     37      1.1  mrg   mpz_sub (t, u, t);
     38      1.1  mrg   if (mpz_sgn (t) < 0 || mpz_cmp (t, r) != 0)
     39      1.1  mrg     {
     40      1.1  mrg       mpz_clear (t);
     41      1.1  mrg       return 0;
     42      1.1  mrg     }
     43      1.1  mrg   mpz_add_ui (t, s, 1);
     44      1.1  mrg   mpz_mul (t, t, t);
     45      1.1  mrg   if (mpz_cmp (t, u) <= 0)
     46      1.1  mrg     {
     47      1.1  mrg       mpz_clear (t);
     48      1.1  mrg       return 0;
     49      1.1  mrg     }
     50      1.1  mrg 
     51      1.1  mrg   mpz_clear (t);
     52      1.1  mrg   return 1;
     53      1.1  mrg }
     54      1.1  mrg 
     55      1.1  mrg void
     56  1.1.1.2  mrg mpz_mpn_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
     57  1.1.1.2  mrg {
     58  1.1.1.2  mrg   mp_limb_t *sp, *rp;
     59  1.1.1.2  mrg   mp_size_t un, sn, ret;
     60  1.1.1.2  mrg 
     61  1.1.1.2  mrg   un = mpz_size (u);
     62  1.1.1.2  mrg 
     63  1.1.1.2  mrg   mpz_xor (s, s, u);
     64  1.1.1.2  mrg   sn = (un + 1) / 2;
     65  1.1.1.2  mrg   sp = mpz_limbs_write (s, sn + 1);
     66  1.1.1.2  mrg   sp [sn] = 11;
     67  1.1.1.2  mrg 
     68  1.1.1.2  mrg   if (un & 1)
     69  1.1.1.2  mrg     rp = NULL; /* Exploits the fact that r already is correct. */
     70  1.1.1.2  mrg   else {
     71  1.1.1.2  mrg     mpz_add (r, u, s);
     72  1.1.1.2  mrg     rp = mpz_limbs_write (r, un + 1);
     73  1.1.1.2  mrg     rp [un] = 19;
     74  1.1.1.2  mrg   }
     75  1.1.1.2  mrg 
     76  1.1.1.2  mrg   ret = mpn_sqrtrem (sp, rp, mpz_limbs_read (u), un);
     77  1.1.1.2  mrg 
     78  1.1.1.2  mrg   if (sp [sn] != 11)
     79  1.1.1.2  mrg     {
     80  1.1.1.2  mrg       fprintf (stderr, "mpn_sqrtrem buffer overrun on sp.\n");
     81  1.1.1.2  mrg       abort ();
     82  1.1.1.2  mrg     }
     83  1.1.1.2  mrg   if (un & 1) {
     84  1.1.1.2  mrg     if ((ret != 0) != (mpz_size (r) != 0)) {
     85  1.1.1.2  mrg       fprintf (stderr, "mpn_sqrtrem wrong return value with NULL.\n");
     86  1.1.1.2  mrg       abort ();
     87  1.1.1.2  mrg     }
     88  1.1.1.2  mrg   } else {
     89  1.1.1.2  mrg     mpz_limbs_finish (r, ret);
     90  1.1.1.2  mrg     if (ret != mpz_size (r)) {
     91  1.1.1.2  mrg       fprintf (stderr, "mpn_sqrtrem wrong return value.\n");
     92  1.1.1.2  mrg       abort ();
     93  1.1.1.2  mrg     }
     94  1.1.1.2  mrg     if (rp [un] != 19)
     95  1.1.1.2  mrg       {
     96  1.1.1.2  mrg 	fprintf (stderr, "mpn_sqrtrem buffer overrun on rp.\n");
     97  1.1.1.2  mrg 	abort ();
     98  1.1.1.2  mrg       }
     99  1.1.1.2  mrg   }
    100  1.1.1.2  mrg 
    101  1.1.1.2  mrg   mpz_limbs_finish (s, (un + 1) / 2);
    102  1.1.1.2  mrg }
    103  1.1.1.2  mrg 
    104  1.1.1.2  mrg void
    105      1.1  mrg testmain (int argc, char **argv)
    106      1.1  mrg {
    107      1.1  mrg   unsigned i;
    108      1.1  mrg   mpz_t u, s, r;
    109      1.1  mrg 
    110      1.1  mrg   mpz_init (s);
    111      1.1  mrg   mpz_init (r);
    112      1.1  mrg 
    113  1.1.1.2  mrg   mpz_init_set_si (u, -1);
    114  1.1.1.2  mrg   if (mpz_perfect_square_p (u))
    115  1.1.1.2  mrg     {
    116  1.1.1.2  mrg       fprintf (stderr, "mpz_perfect_square_p failed on -1.\n");
    117  1.1.1.2  mrg       abort ();
    118  1.1.1.2  mrg     }
    119  1.1.1.2  mrg 
    120  1.1.1.2  mrg   if (!mpz_perfect_square_p (s))
    121  1.1.1.2  mrg     {
    122  1.1.1.2  mrg       fprintf (stderr, "mpz_perfect_square_p failed on 0.\n");
    123  1.1.1.2  mrg       abort ();
    124  1.1.1.2  mrg     }
    125  1.1.1.2  mrg 
    126      1.1  mrg   for (i = 0; i < COUNT; i++)
    127      1.1  mrg     {
    128  1.1.1.2  mrg       mini_rrandomb (u, MAXBITS - (i & 0xFF));
    129      1.1  mrg       mpz_sqrtrem (s, r, u);
    130      1.1  mrg 
    131      1.1  mrg       if (!sqrtrem_valid_p (u, s, r))
    132      1.1  mrg 	{
    133      1.1  mrg 	  fprintf (stderr, "mpz_sqrtrem failed:\n");
    134      1.1  mrg 	  dump ("u", u);
    135      1.1  mrg 	  dump ("sqrt", s);
    136      1.1  mrg 	  dump ("rem", r);
    137      1.1  mrg 	  abort ();
    138      1.1  mrg 	}
    139  1.1.1.2  mrg 
    140  1.1.1.2  mrg       mpz_mpn_sqrtrem (s, r, u);
    141  1.1.1.2  mrg 
    142  1.1.1.2  mrg       if (!sqrtrem_valid_p (u, s, r))
    143  1.1.1.2  mrg 	{
    144  1.1.1.2  mrg 	  fprintf (stderr, "mpn_sqrtrem failed:\n");
    145  1.1.1.2  mrg 	  dump ("u", u);
    146  1.1.1.2  mrg 	  dump ("sqrt", s);
    147  1.1.1.2  mrg 	  dump ("rem", r);
    148  1.1.1.2  mrg 	  abort ();
    149  1.1.1.2  mrg 	}
    150  1.1.1.2  mrg 
    151  1.1.1.2  mrg       if (mpz_sgn (r) == 0) {
    152  1.1.1.2  mrg 	mpz_neg (u, u);
    153  1.1.1.2  mrg 	mpz_sub_ui (u, u, 1);
    154  1.1.1.2  mrg       }
    155  1.1.1.2  mrg 
    156  1.1.1.2  mrg       if ((mpz_sgn (u) <= 0 || (i & 1)) ?
    157  1.1.1.2  mrg 	  mpz_perfect_square_p (u) :
    158  1.1.1.2  mrg 	  mpn_perfect_square_p (mpz_limbs_read (u), mpz_size (u)))
    159  1.1.1.2  mrg 	{
    160  1.1.1.2  mrg 	  fprintf (stderr, "mp%s_perfect_square_p failed on non square:\n",
    161  1.1.1.2  mrg 		   (mpz_sgn (u) <= 0 || (i & 1)) ? "z" : "n");
    162  1.1.1.2  mrg 	  dump ("u", u);
    163  1.1.1.2  mrg 	  abort ();
    164  1.1.1.2  mrg 	}
    165  1.1.1.2  mrg 
    166  1.1.1.2  mrg       mpz_mul (u, s, s);
    167  1.1.1.2  mrg       if (!((mpz_sgn (u) <= 0 || (i & 1)) ?
    168  1.1.1.2  mrg 	    mpz_perfect_square_p (u) :
    169  1.1.1.2  mrg 	    mpn_perfect_square_p (mpz_limbs_read (u), mpz_size (u))))
    170  1.1.1.2  mrg 	{
    171  1.1.1.2  mrg 	  fprintf (stderr, "mp%s_perfect_square_p failed on square:\n",
    172  1.1.1.2  mrg 		   (mpz_sgn (u) <= 0 || (i & 1)) ? "z" : "n");
    173  1.1.1.2  mrg 	  dump ("u", u);
    174  1.1.1.2  mrg 	  abort ();
    175  1.1.1.2  mrg 	}
    176  1.1.1.2  mrg 
    177      1.1  mrg     }
    178      1.1  mrg   mpz_clear (u);
    179      1.1  mrg   mpz_clear (s);
    180      1.1  mrg   mpz_clear (r);
    181      1.1  mrg }
    182