(root)/
gmp-6.3.0/
tests/
mpn/
t-invert.c
       1  /* Test for mpn_invert function.
       2  
       3     Contributed to the GNU project by Marco Bodrato.
       4  
       5  Copyright 2009 Free Software Foundation, Inc.
       6  
       7  This file is part of the GNU MP Library test suite.
       8  
       9  The GNU MP Library test suite is free software; you can redistribute it
      10  and/or modify it under the terms of the GNU General Public License as
      11  published by the Free Software Foundation; either version 3 of the License,
      12  or (at your option) any later version.
      13  
      14  The GNU MP Library test suite is distributed in the hope that it will be
      15  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
      16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
      17  Public License for more details.
      18  
      19  You should have received a copy of the GNU General Public License along with
      20  the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
      21  
      22  
      23  #include <stdlib.h>
      24  #include <stdio.h>
      25  
      26  #include "gmp-impl.h"
      27  #include "tests.h"
      28  
      29  /* Sizes are up to 2^SIZE_LOG limbs */
      30  #ifndef SIZE_LOG
      31  #define SIZE_LOG 12
      32  #endif
      33  
      34  #ifndef COUNT
      35  #define COUNT 1000
      36  #endif
      37  
      38  #define MAX_N (1L << SIZE_LOG)
      39  #define MIN_N 1
      40  
      41  
      42  static int
      43  invert_valid (mp_srcptr ip, mp_srcptr dp, mp_size_t n)
      44  {
      45    mp_ptr tp;
      46    int cy;
      47    TMP_DECL;
      48  
      49    TMP_MARK;
      50    tp = TMP_ALLOC_LIMBS (2*n);
      51  
      52    refmpn_mul (tp, ip, n, dp, n);
      53    cy  = refmpn_add_n (tp + n, tp + n, dp, n); /* This must not give a carry. */
      54    cy -= refmpn_add (tp, tp, 2*n, dp, n); /* This must give a carry. */
      55    TMP_FREE;
      56  
      57    return (cy == -1);
      58  }
      59  
      60  /*
      61    Check the result of the mpn_invert function in the library.
      62  */
      63  
      64  int
      65  main (int argc, char **argv)
      66  {
      67    mp_ptr ip, dp, scratch;
      68    int count = COUNT;
      69    int test;
      70    gmp_randstate_ptr rands;
      71    TMP_DECL;
      72    TMP_MARK;
      73  
      74    TESTS_REPS (count, argv, argc);
      75  
      76    tests_start ();
      77    rands = RANDS;
      78  
      79    dp = TMP_ALLOC_LIMBS (MAX_N);
      80    ip = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
      81    scratch
      82      = 1+TMP_ALLOC_LIMBS (mpn_invert_itch (MAX_N) + 2);
      83  
      84    for (test = 0; test < count; test++)
      85      {
      86        unsigned size_min;
      87        unsigned size_range;
      88        mp_size_t n;
      89        mp_size_t itch;
      90        mp_limb_t i_before, i_after, s_before, s_after;
      91  
      92        for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
      93  	;
      94  
      95        /* We generate an in the MIN_N <= n <= (1 << size_range). */
      96        size_range = size_min
      97  	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
      98  
      99        n = MIN_N
     100  	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
     101  
     102        mpn_random2 (dp, n);
     103  
     104        mpn_random2 (ip-1, n + 2);
     105        i_before = ip[-1];
     106        i_after = ip[n];
     107  
     108        itch = mpn_invert_itch (n);
     109        ASSERT_ALWAYS (itch <= mpn_invert_itch (MAX_N));
     110        mpn_random2 (scratch-1, itch+2);
     111        s_before = scratch[-1];
     112        s_after = scratch[itch];
     113  
     114        dp[n-1] |= GMP_NUMB_HIGHBIT;
     115        mpn_invert (ip, dp, n, scratch);
     116        if (ip[-1] != i_before || ip[n] != i_after
     117  	  || scratch[-1] != s_before || scratch[itch] != s_after
     118  	  || ! invert_valid(ip, dp, n))
     119  	{
     120  	  printf ("ERROR in test %d, n = %d\n",
     121  		  test, (int) n);
     122  	  if (ip[-1] != i_before)
     123  	    {
     124  	      printf ("before ip:"); mpn_dump (ip -1, 1);
     125  	      printf ("keep:   "); mpn_dump (&i_before, 1);
     126  	    }
     127  	  if (ip[n] != i_after)
     128  	    {
     129  	      printf ("after ip:"); mpn_dump (ip + n, 1);
     130  	      printf ("keep:   "); mpn_dump (&i_after, 1);
     131  	    }
     132  	  if (scratch[-1] != s_before)
     133  	    {
     134  	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
     135  	      printf ("keep:   "); mpn_dump (&s_before, 1);
     136  	    }
     137  	  if (scratch[itch] != s_after)
     138  	    {
     139  	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
     140  	      printf ("keep:   "); mpn_dump (&s_after, 1);
     141  	    }
     142  	  mpn_dump (dp, n);
     143  	  mpn_dump (ip, n);
     144  
     145  	  abort();
     146  	}
     147      }
     148    TMP_FREE;
     149    tests_end ();
     150    return 0;
     151  }