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

数学计算

开发平台:

Unix_Linux

  1. /* Test mpz_gcd, mpz_gcdext, and mpz_gcd_ui.
  2. Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005,
  3. 2008, 2009 Free Software Foundation, Inc.
  4. This file is part of the GNU MP Library.
  5. The GNU MP Library is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or (at your
  8. option) any later version.
  9. The GNU MP Library is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  12. License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include "gmp.h"
  18. #include "gmp-impl.h"
  19. #include "tests.h"
  20. void one_test __GMP_PROTO ((mpz_t, mpz_t, mpz_t, int));
  21. void debug_mp __GMP_PROTO ((mpz_t, int));
  22. static int gcdext_valid_p __GMP_PROTO ((const mpz_t a, const mpz_t b, const mpz_t g, const mpz_t s));
  23. void
  24. check_data (void)
  25. {
  26.   static const struct {
  27.     const char *a;
  28.     const char *b;
  29.     const char *want;
  30.   } data[] = {
  31.     /* This tickled a bug in gmp 4.1.2 mpn/x86/k6/gcd_finda.asm. */
  32.     { "0x3FFC000007FFFFFFFFFF00000000003F83FFFFFFFFFFFFFFF80000000000000001",
  33.       "0x1FFE0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000000000000000000000001",
  34.       "5" }
  35.   };
  36.   mpz_t  a, b, got, want;
  37.   int    i;
  38.   mpz_init (a);
  39.   mpz_init (b);
  40.   mpz_init (got);
  41.   mpz_init (want);
  42.   for (i = 0; i < numberof (data); i++)
  43.     {
  44.       mpz_set_str_or_abort (a, data[i].a, 0);
  45.       mpz_set_str_or_abort (b, data[i].b, 0);
  46.       mpz_set_str_or_abort (want, data[i].want, 0);
  47.       mpz_gcd (got, a, b);
  48.       MPZ_CHECK_FORMAT (got);
  49.       if (mpz_cmp (got, want) != 0)
  50. {
  51.   printf    ("mpz_gcd wrong on data[%d]n", i);
  52.   printf    (" a  %sn", data[i].a);
  53.   printf    (" b  %sn", data[i].b);
  54.   mpz_trace (" a", a);
  55.   mpz_trace (" b", b);
  56.   mpz_trace (" want", want);
  57.   mpz_trace (" got ", got);
  58.   abort ();
  59. }
  60.     }
  61.   mpz_clear (a);
  62.   mpz_clear (b);
  63.   mpz_clear (got);
  64.   mpz_clear (want);
  65. }
  66. /* Keep one_test's variables global, so that we don't need
  67.    to reinitialize them for each test.  */
  68. mpz_t gcd1, gcd2, s, t, temp1, temp2, temp3;
  69. #if GCD_DC_THRESHOLD > GCDEXT_DC_THRESHOLD
  70. #define MAX_SCHOENHAGE_THRESHOLD GCD_DC_THRESHOLD
  71. #else
  72. #define MAX_SCHOENHAGE_THRESHOLD GCDEXT_DC_THRESHOLD
  73. #endif
  74. /* Define this to make all operands be large enough for Schoenhage gcd
  75.    to be used.  */
  76. #ifndef WHACK_SCHOENHAGE
  77. #define WHACK_SCHOENHAGE 0
  78. #endif
  79. #if WHACK_SCHOENHAGE
  80. #define MIN_OPERAND_BITSIZE (MAX_SCHOENHAGE_THRESHOLD * GMP_NUMB_BITS)
  81. #else
  82. #define MIN_OPERAND_BITSIZE 1
  83. #endif
  84. int
  85. main (int argc, char **argv)
  86. {
  87.   mpz_t op1, op2, ref;
  88.   int i, j, chain_len;
  89.   gmp_randstate_ptr rands;
  90.   mpz_t bs;
  91.   unsigned long bsi, size_range;
  92.   int reps = 200;
  93.   tests_start ();
  94.   TESTS_REPS (reps, argv, argc);
  95.   rands = RANDS;
  96.   check_data ();
  97.   mpz_init (bs);
  98.   mpz_init (op1);
  99.   mpz_init (op2);
  100.   mpz_init (ref);
  101.   mpz_init (gcd1);
  102.   mpz_init (gcd2);
  103.   mpz_init (temp1);
  104.   mpz_init (temp2);
  105.   mpz_init (temp3);
  106.   mpz_init (s);
  107.   mpz_init (t);
  108.   /* Testcase to exercise the u0 == u1 case in mpn_gcdext_lehmer_n. */
  109.   mpz_set_ui (op2, GMP_NUMB_MAX);
  110.   mpz_mul_2exp (op1, op2, 100);
  111.   mpz_add (op1, op1, op2);
  112.   mpz_mul_ui (op2, op2, 2);
  113.   one_test (op1, op2, NULL, -1);
  114. #if 0
  115.   mpz_set_str (op1, "4da8e405e0d2f70d6d679d3de08a5100a81ec2cff40f97b313ae75e1183f1df2b244e194ebb02a4ece50d943640a301f0f6cc7f539117b783c3f3a3f91649f8a00d2e1444d52722810562bce02fccdbbc8fe3276646e306e723dd3b", 16);
  116.   mpz_set_str (op2, "76429e12e4fdd8929d89c21657097fbac09d1dc08cf7f1323a34e78ca34226e1a7a29b86fee0fa7fe2cc2a183d46d50df1fe7029590974ad7da77605f35f902cb8b9b8d22dd881eaae5919675d49a337145a029c3b33fc2b0", 16);
  117.   one_test (op1, op2, NULL, -1);
  118. #endif
  119.   for (i = 0; i < reps; i++)
  120.     {
  121.       /* Generate plain operands with unknown gcd.  These types of operands
  122.  have proven to trigger certain bugs in development versions of the
  123.  gcd code.  The "hgcd->row[3].rsize > M" ASSERT is not triggered by
  124.  the division chain code below, but that is most likely just a result
  125.  of that other ASSERTs are triggered before it.  */
  126.       mpz_urandomb (bs, rands, 32);
  127.       size_range = mpz_get_ui (bs) % 17 + 2;
  128.       mpz_urandomb (bs, rands, size_range);
  129.       mpz_urandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
  130.       mpz_urandomb (bs, rands, size_range);
  131.       mpz_urandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
  132.       mpz_urandomb (bs, rands, 8);
  133.       bsi = mpz_get_ui (bs);
  134.       if ((bsi & 0x3c) == 4)
  135. mpz_mul (op1, op1, op2); /* make op1 a multiple of op2 */
  136.       else if ((bsi & 0x3c) == 8)
  137. mpz_mul (op2, op1, op2); /* make op2 a multiple of op1 */
  138.       if ((bsi & 1) != 0)
  139. mpz_neg (op1, op1);
  140.       if ((bsi & 2) != 0)
  141. mpz_neg (op2, op2);
  142.       one_test (op1, op2, NULL, i);
  143.       /* Generate a division chain backwards, allowing otherwise unlikely huge
  144.  quotients.  */
  145.       mpz_set_ui (op1, 0);
  146.       mpz_urandomb (bs, rands, 32);
  147.       mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
  148.       mpz_rrandomb (op2, rands, mpz_get_ui (bs));
  149.       mpz_add_ui (op2, op2, 1);
  150.       mpz_set (ref, op2);
  151. #if WHACK_SCHOENHAGE
  152.       chain_len = 1000000;
  153. #else
  154.       mpz_urandomb (bs, rands, 32);
  155.       chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * MAX_SCHOENHAGE_THRESHOLD / 256);
  156. #endif
  157.       for (j = 0; j < chain_len; j++)
  158. {
  159.   mpz_urandomb (bs, rands, 32);
  160.   mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
  161.   mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
  162.   mpz_add_ui (temp2, temp2, 1);
  163.   mpz_mul (temp1, op2, temp2);
  164.   mpz_add (op1, op1, temp1);
  165.   /* Don't generate overly huge operands.  */
  166.   if (SIZ (op1) > 3 * MAX_SCHOENHAGE_THRESHOLD)
  167.     break;
  168.   mpz_urandomb (bs, rands, 32);
  169.   mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
  170.   mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
  171.   mpz_add_ui (temp2, temp2, 1);
  172.   mpz_mul (temp1, op1, temp2);
  173.   mpz_add (op2, op2, temp1);
  174.   /* Don't generate overly huge operands.  */
  175.   if (SIZ (op2) > 3 * MAX_SCHOENHAGE_THRESHOLD)
  176.     break;
  177. }
  178.       one_test (op1, op2, ref, i);
  179.     }
  180.   mpz_clear (bs);
  181.   mpz_clear (op1);
  182.   mpz_clear (op2);
  183.   mpz_clear (ref);
  184.   mpz_clear (gcd1);
  185.   mpz_clear (gcd2);
  186.   mpz_clear (temp1);
  187.   mpz_clear (temp2);
  188.   mpz_clear (temp3);
  189.   mpz_clear (s);
  190.   mpz_clear (t);
  191.   tests_end ();
  192.   exit (0);
  193. }
  194. void
  195. debug_mp (mpz_t x, int base)
  196. {
  197.   mpz_out_str (stderr, base, x); fputc ('n', stderr);
  198. }
  199. void
  200. one_test (mpz_t op1, mpz_t op2, mpz_t ref, int i)
  201. {
  202.   /*
  203.   printf ("%ld %ld %ldn", SIZ (op1), SIZ (op2), SIZ (ref));
  204.   fflush (stdout);
  205.   */
  206.   /*
  207.   fprintf (stderr, "op1=");  debug_mp (op1, -16);
  208.   fprintf (stderr, "op2=");  debug_mp (op2, -16);
  209.   */
  210.   mpz_gcdext (gcd1, s, NULL, op1, op2);
  211.   MPZ_CHECK_FORMAT (gcd1);
  212.   MPZ_CHECK_FORMAT (s);
  213.   if (ref && mpz_cmp (ref, gcd1) != 0)
  214.     {
  215.       fprintf (stderr, "ERROR in test %dn", i);
  216.       fprintf (stderr, "mpz_gcdext returned incorrect resultn");
  217.       fprintf (stderr, "op1=");                 debug_mp (op1, -16);
  218.       fprintf (stderr, "op2=");                 debug_mp (op2, -16);
  219.       fprintf (stderr, "expected result:n");   debug_mp (ref, -16);
  220.       fprintf (stderr, "mpz_gcdext returns:n");debug_mp (gcd1, -16);
  221.       abort ();
  222.     }
  223.   if (!gcdext_valid_p(op1, op2, gcd1, s))
  224.     {
  225.       fprintf (stderr, "ERROR in test %dn", i);
  226.       fprintf (stderr, "mpz_gcdext returned invalid resultn");
  227.       fprintf (stderr, "op1=");                 debug_mp (op1, -16);
  228.       fprintf (stderr, "op2=");                 debug_mp (op2, -16);
  229.       fprintf (stderr, "mpz_gcdext returns:n");debug_mp (gcd1, -16);
  230.       fprintf (stderr, "s=");                   debug_mp (s, -16);
  231.       abort ();
  232.     }
  233.   mpz_gcd (gcd2, op1, op2);
  234.   MPZ_CHECK_FORMAT (gcd2);
  235.   if (mpz_cmp (gcd2, gcd1) != 0)
  236.     {
  237.       fprintf (stderr, "ERROR in test %dn", i);
  238.       fprintf (stderr, "mpz_gcd returned incorrect resultn");
  239.       fprintf (stderr, "op1=");                 debug_mp (op1, -16);
  240.       fprintf (stderr, "op2=");                 debug_mp (op2, -16);
  241.       fprintf (stderr, "expected result:n");   debug_mp (gcd1, -16);
  242.       fprintf (stderr, "mpz_gcd returns:n");   debug_mp (gcd2, -16);
  243.       abort ();
  244.     }
  245.   /* This should probably move to t-gcd_ui.c */
  246.   if (mpz_fits_ulong_p (op1) || mpz_fits_ulong_p (op2))
  247.     {
  248.       if (mpz_fits_ulong_p (op1))
  249. mpz_gcd_ui (gcd2, op2, mpz_get_ui (op1));
  250.       else
  251. mpz_gcd_ui (gcd2, op1, mpz_get_ui (op2));
  252.       if (mpz_cmp (gcd2, gcd1))
  253. {
  254.   fprintf (stderr, "ERROR in test %dn", i);
  255.   fprintf (stderr, "mpz_gcd_ui returned incorrect resultn");
  256.   fprintf (stderr, "op1=");                 debug_mp (op1, -16);
  257.   fprintf (stderr, "op2=");                 debug_mp (op2, -16);
  258.   fprintf (stderr, "expected result:n");   debug_mp (gcd1, -16);
  259.   fprintf (stderr, "mpz_gcd_ui returns:n");   debug_mp (gcd2, -16);
  260.   abort ();
  261. }
  262.     }
  263.   mpz_gcdext (gcd2, temp1, temp2, op1, op2);
  264.   MPZ_CHECK_FORMAT (gcd2);
  265.   MPZ_CHECK_FORMAT (temp1);
  266.   MPZ_CHECK_FORMAT (temp2);
  267.   mpz_mul (temp1, temp1, op1);
  268.   mpz_mul (temp2, temp2, op2);
  269.   mpz_add (temp1, temp1, temp2);
  270.   if (mpz_cmp (gcd1, gcd2) != 0
  271.       || mpz_cmp (gcd2, temp1) != 0)
  272.     {
  273.       fprintf (stderr, "ERROR in test %dn", i);
  274.       fprintf (stderr, "mpz_gcdext returned incorrect resultn");
  275.       fprintf (stderr, "op1=");                 debug_mp (op1, -16);
  276.       fprintf (stderr, "op2=");                 debug_mp (op2, -16);
  277.       fprintf (stderr, "expected result:n");   debug_mp (gcd1, -16);
  278.       fprintf (stderr, "mpz_gcdext returns:n");debug_mp (gcd2, -16);
  279.       abort ();
  280.     }
  281. }
  282. /* Called when g is supposed to be gcd(a,b), and g = s a + t b, for some t.
  283.    Uses temp1, temp2 and temp3. */
  284. static int
  285. gcdext_valid_p (const mpz_t a, const mpz_t b, const mpz_t g, const mpz_t s)
  286. {
  287.   /* It's not clear that gcd(0,0) is well defined, but we allow it and require that
  288.      gcd(0,0) = 0. */
  289.   if (mpz_sgn (g) < 0)
  290.     return 0;
  291.   if (mpz_sgn (a) == 0)
  292.     {
  293.       /* Must have g == abs (b). Any value for s is in some sense "correct",
  294.  but it makes sense to require that s == 0. */
  295.       return mpz_cmpabs (g, b) == 0 && mpz_sgn (s) == 0;
  296.     }
  297.   else if (mpz_sgn (b) == 0)
  298.     {
  299.       /* Must have g == abs (a), s == sign (a) */
  300.       return mpz_cmpabs (g, a) == 0 && mpz_cmp_si (s, mpz_sgn (a)) == 0;
  301.     }
  302.   if (mpz_sgn (g) <= 0)
  303.     return 0;
  304.   mpz_tdiv_qr (temp1, temp3, a, g);
  305.   if (mpz_sgn (temp3) != 0)
  306.     return 0;
  307.   mpz_tdiv_qr (temp2, temp3, b, g);
  308.   if (mpz_sgn (temp3) != 0)
  309.     return 0;
  310.   /* Require that 2 |s| < |b/g|, or |s| == 1. */
  311.   if (mpz_cmpabs_ui (s, 1) > 0)
  312.     {
  313.       mpz_mul_2exp (temp3, s, 1);
  314.       if (mpz_cmpabs (temp3, temp2) > 0)
  315. return 0;
  316.     }
  317.   /* Compute the other cofactor. */
  318.   mpz_mul(temp2, s, a);
  319.   mpz_sub(temp2, g, temp2);
  320.   mpz_tdiv_qr(temp2, temp3, temp2, b);
  321.   if (mpz_sgn (temp3) != 0)
  322.     return 0;
  323.   /* Require that 2 |t| < |a/g| or |t| == 1*/
  324.   if (mpz_cmpabs_ui (temp2, 1) > 0)
  325.     {
  326.       mpz_mul_2exp (temp2, temp2, 1);
  327.       if (mpz_cmpabs (temp2, temp1) > 0)
  328. return 0;
  329.     }
  330.   return 1;
  331. }