(root)/
gmp-6.3.0/
tests/
mpz/
t-div_2exp.c
       1  /* Test mpz_[cft]div_[qr]_2exp.
       2  
       3  Copyright 2001 Free Software Foundation, Inc.
       4  
       5  This file is part of the GNU MP Library test suite.
       6  
       7  The GNU MP Library test suite is free software; you can redistribute it
       8  and/or modify it under the terms of the GNU General Public License as
       9  published by the Free Software Foundation; either version 3 of the License,
      10  or (at your option) any later version.
      11  
      12  The GNU MP Library test suite is distributed in the hope that it will be
      13  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
      14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
      15  Public License for more details.
      16  
      17  You should have received a copy of the GNU General Public License along with
      18  the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
      19  
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  
      23  #include "gmp-impl.h"
      24  #include "tests.h"
      25  
      26  
      27  /* If the remainder is in the correct range and q*d+r is correct, then q
      28     must have rounded correctly.  */
      29  
      30  void
      31  check_one (mpz_srcptr a, unsigned long d)
      32  {
      33    mpz_t  q, r, p, d2exp;
      34    int    inplace;
      35  
      36    mpz_init (d2exp);
      37    mpz_init (q);
      38    mpz_init (r);
      39    mpz_init (p);
      40  
      41    mpz_set_ui (d2exp, 1L);
      42    mpz_mul_2exp (d2exp, d2exp, d);
      43  
      44  #define INPLACE(fun,dst,src,d)  \
      45    if (inplace)                  \
      46      {                           \
      47        mpz_set (dst, src);       \
      48        fun (dst, dst, d);        \
      49      }                           \
      50    else                          \
      51      fun (dst, src, d);
      52  
      53    for (inplace = 0; inplace <= 1; inplace++)
      54      {
      55        INPLACE (mpz_fdiv_q_2exp, q, a, d);
      56        INPLACE (mpz_fdiv_r_2exp, r, a, d);
      57  
      58        mpz_mul_2exp (p, q, d);
      59        mpz_add (p, p, r);
      60        if (mpz_sgn (r) < 0 || mpz_cmp (r, d2exp) >= 0)
      61  	{
      62  	  printf ("mpz_fdiv_r_2exp result out of range\n");
      63  	  goto error;
      64  	}
      65        if (mpz_cmp (p, a) != 0)
      66  	{
      67  	  printf ("mpz_fdiv_[qr]_2exp doesn't multiply back\n");
      68  	  goto error;
      69  	}
      70  
      71  
      72        INPLACE (mpz_cdiv_q_2exp, q, a, d);
      73        INPLACE (mpz_cdiv_r_2exp, r, a, d);
      74  
      75        mpz_mul_2exp (p, q, d);
      76        mpz_add (p, p, r);
      77        if (mpz_sgn (r) > 0 || mpz_cmpabs (r, d2exp) >= 0)
      78  	{
      79  	  printf ("mpz_cdiv_r_2exp result out of range\n");
      80  	  goto error;
      81  	}
      82        if (mpz_cmp (p, a) != 0)
      83  	{
      84  	  printf ("mpz_cdiv_[qr]_2exp doesn't multiply back\n");
      85  	  goto error;
      86  	}
      87  
      88  
      89        INPLACE (mpz_tdiv_q_2exp, q, a, d);
      90        INPLACE (mpz_tdiv_r_2exp, r, a, d);
      91  
      92        mpz_mul_2exp (p, q, d);
      93        mpz_add (p, p, r);
      94        if (mpz_sgn (r) != 0 && mpz_sgn (r) != mpz_sgn (a))
      95  	{
      96  	  printf ("mpz_tdiv_r_2exp result wrong sign\n");
      97  	  goto error;
      98  	}
      99        if (mpz_cmpabs (r, d2exp) >= 0)
     100  	{
     101  	  printf ("mpz_tdiv_r_2exp result out of range\n");
     102  	  goto error;
     103  	}
     104        if (mpz_cmp (p, a) != 0)
     105  	{
     106  	  printf ("mpz_tdiv_[qr]_2exp doesn't multiply back\n");
     107  	  goto error;
     108  	}
     109      }
     110  
     111    mpz_clear (d2exp);
     112    mpz_clear (q);
     113    mpz_clear (r);
     114    mpz_clear (p);
     115    return;
     116  
     117  
     118   error:
     119    mpz_trace ("a", a);
     120    printf    ("d=%lu\n", d);
     121    mpz_trace ("q", q);
     122    mpz_trace ("r", r);
     123    mpz_trace ("p", p);
     124  
     125    mp_trace_base = -16;
     126    mpz_trace ("a", a);
     127    printf    ("d=0x%lX\n", d);
     128    mpz_trace ("q", q);
     129    mpz_trace ("r", r);
     130    mpz_trace ("p", p);
     131  
     132    abort ();
     133  }
     134  
     135  
     136  void
     137  check_all (mpz_ptr a, unsigned long d)
     138  {
     139    check_one (a, d);
     140    mpz_neg (a, a);
     141    check_one (a, d);
     142  }
     143  
     144  
     145  void
     146  check_various (void)
     147  {
     148    static const unsigned long  table[] = {
     149      0, 1, 2, 3, 4, 5,
     150      GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
     151      2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
     152      3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
     153      4*GMP_NUMB_BITS-1, 4*GMP_NUMB_BITS, 4*GMP_NUMB_BITS+1
     154    };
     155  
     156    int            i, j;
     157    unsigned long  n, d;
     158    mpz_t          a;
     159  
     160    mpz_init (a);
     161  
     162    /* a==0, and various d */
     163    mpz_set_ui (a, 0L);
     164    for (i = 0; i < numberof (table); i++)
     165      check_one (a, table[i]);
     166  
     167    /* a==2^n, and various d */
     168    for (i = 0; i < numberof (table); i++)
     169      {
     170        n = table[i];
     171        mpz_set_ui (a, 1L);
     172        mpz_mul_2exp (a, a, n);
     173  
     174        for (j = 0; j < numberof (table); j++)
     175  	{
     176  	  d = table[j];
     177  	  check_all (a, d);
     178  	}
     179      }
     180  
     181    mpz_clear (a);
     182  }
     183  
     184  
     185  void
     186  check_random (int argc, char *argv[])
     187  {
     188    gmp_randstate_ptr  rands = RANDS;
     189    int            reps = 100;
     190    mpz_t          a;
     191    unsigned long  d;
     192    int            i;
     193  
     194    if (argc == 2)
     195      reps = atoi (argv[1]);
     196  
     197    mpz_init (a);
     198  
     199    for (i = 0; i < reps; i++)
     200      {
     201        /* exponentially within 2 to 257 bits */
     202        mpz_erandomb (a, rands, urandom () % 8 + 2);
     203  
     204        d = urandom () % 256;
     205  
     206        check_all (a, d);
     207      }
     208  
     209    mpz_clear (a);
     210  }
     211  
     212  
     213  int
     214  main (int argc, char *argv[])
     215  {
     216    tests_start ();
     217  
     218    check_various ();
     219    check_random (argc, argv);
     220  
     221    tests_end ();
     222    exit (0);
     223  }