📄 t-mul.c
字号:
/* Test mpz_cmp, mpz_mul.Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2002, 2003, 2004 FreeSoftware Foundation, Inc.This file is part of the GNU MP Library.The GNU MP Library is free software; you can redistribute it and/or modifyit under the terms of the GNU Lesser General Public License as published bythe Free Software Foundation; either version 2.1 of the License, or (at youroption) any later version.The GNU MP Library is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITYor FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General PublicLicense for more details.You should have received a copy of the GNU Lesser General Public Licensealong with the GNU MP Library; see the file COPYING.LIB. If not, write tothe Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,MA 02111-1307, USA. */#include <stdio.h>#include <stdlib.h>#include "gmp.h"#include "gmp-impl.h"#include "longlong.h"#include "tests.h"void debug_mp _PROTO ((mpz_t));static void ref_mpn_mul _PROTO ((mp_ptr,mp_srcptr,mp_size_t,mp_srcptr,mp_size_t));static void ref_mpz_mul _PROTO ((mpz_t, const mpz_t, const mpz_t));void dump_abort _PROTO ((int, char *, mpz_t, mpz_t, mpz_t, mpz_t));#define FFT_MIN_BITSIZE 100000char *extra_fft;voidone (int i, mpz_t multiplicand, mpz_t multiplier){ mpz_t product, ref_product; mpz_t quotient; mpz_init (product); mpz_init (ref_product); mpz_init (quotient); /* Test plain multiplication comparing results against reference code. */ mpz_mul (product, multiplier, multiplicand); ref_mpz_mul (ref_product, multiplier, multiplicand); if (mpz_cmp (product, ref_product)) dump_abort (i, "incorrect plain product", multiplier, multiplicand, product, ref_product); /* Test squaring, comparing results against plain multiplication */ mpz_mul (product, multiplier, multiplier); mpz_set (multiplicand, multiplier); mpz_mul (ref_product, multiplier, multiplicand); if (mpz_cmp (product, ref_product)) dump_abort (i, "incorrect square product", multiplier, multiplier, product, ref_product); mpz_clear (product); mpz_clear (ref_product); mpz_clear (quotient);}intmain (int argc, char **argv){ mpz_t op1, op2; int i; gmp_randstate_ptr rands; mpz_t bs; unsigned long bsi, size_range, fsize_range; tests_start (); rands = RANDS; extra_fft = getenv ("GMP_CHECK_FFT"); mpz_init (bs); mpz_init (op1); mpz_init (op2); fsize_range = 4 << 8; /* a fraction 1/256 of size_range */ for (i = 0; fsize_range >> 8 < (extra_fft ? 27 : 22); i++) { size_range = fsize_range >> 8; fsize_range = fsize_range * 33 / 32; mpz_urandomb (bs, rands, size_range); mpz_rrandomb (op1, rands, mpz_get_ui (bs)); mpz_urandomb (bs, rands, size_range); mpz_rrandomb (op2, rands, mpz_get_ui (bs)); mpz_urandomb (bs, rands, 4); bsi = mpz_get_ui (bs); if ((bsi & 0x3) == 0) mpz_neg (op1, op1); if ((bsi & 0xC) == 0) mpz_neg (op2, op2); /* printf ("%d %d\n", SIZ (op1), SIZ (op2)); */ one (i, op2, op1); } if (extra_fft) for (i = -50; i < 0; i++) { mpz_urandomb (bs, rands, 32); size_range = mpz_get_ui (bs) % 27; mpz_urandomb (bs, rands, size_range); mpz_rrandomb (op1, rands, mpz_get_ui (bs) + FFT_MIN_BITSIZE); mpz_urandomb (bs, rands, size_range); mpz_rrandomb (op2, rands, mpz_get_ui (bs) + FFT_MIN_BITSIZE); /* printf ("%d: %d %d\n", i, SIZ (op1), SIZ (op2)); */ fflush (stdout); one (-1, op2, op1); } mpz_clear (bs); mpz_clear (op1); mpz_clear (op2); tests_end (); exit (0);}static voidref_mpz_mul (mpz_t w, const mpz_t u, const mpz_t v){ mp_size_t usize = u->_mp_size; mp_size_t vsize = v->_mp_size; mp_size_t wsize; mp_size_t sign_product; mp_ptr up, vp; mp_ptr wp; mp_size_t talloc; sign_product = usize ^ vsize; usize = ABS (usize); vsize = ABS (vsize); if (usize == 0 || vsize == 0) { SIZ (w) = 0; return; } talloc = usize + vsize; up = u->_mp_d; vp = v->_mp_d; wp = __GMP_ALLOCATE_FUNC_LIMBS (talloc); if (usize > vsize) ref_mpn_mul (wp, up, usize, vp, vsize); else ref_mpn_mul (wp, vp, vsize, up, usize); wsize = usize + vsize; wsize -= wp[wsize - 1] == 0; MPZ_REALLOC (w, wsize); MPN_COPY (PTR(w), wp, wsize); SIZ(w) = sign_product < 0 ? -wsize : wsize; __GMP_FREE_FUNC_LIMBS (wp, talloc);}static void mul_basecase __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t));#define TOOM3_THRESHOLD (MAX (MUL_TOOM3_THRESHOLD, SQR_TOOM3_THRESHOLD))#define FFT_THRESHOLD (MAX (MUL_FFT_THRESHOLD, SQR_FFT_THRESHOLD))static voidref_mpn_mul (mp_ptr wp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn){ mp_ptr tp; mp_size_t tn; mp_limb_t cy; if (vn < TOOM3_THRESHOLD) { /* In the mpn_mul_basecase and mpn_kara_mul_n range, use our own mul_basecase. */ if (vn != 0) mul_basecase (wp, up, un, vp, vn); else MPN_ZERO (wp, un); return; } if (vn < FFT_THRESHOLD) { /* In the mpn_toom3_mul_n range, use mpn_kara_mul_n. */ tn = 2 * vn + MPN_KARA_MUL_N_TSIZE (vn); tp = __GMP_ALLOCATE_FUNC_LIMBS (tn); mpn_kara_mul_n (tp, up, vp, vn, tp + 2 * vn); } else { /* Finally, for the largest operands, use mpn_toom3_mul_n. */ /* The "- 63 + 255" tweaks the allocation to allow for huge operands. See the definition of this macro in gmp-impl.h to understand this. */ tn = 2 * vn + MPN_TOOM3_MUL_N_TSIZE (vn) - 63 + 255; tp = __GMP_ALLOCATE_FUNC_LIMBS (tn); mpn_toom3_mul_n (tp, up, vp, vn, tp + 2 * vn); } if (un != vn) { if (un - vn < vn) ref_mpn_mul (wp + vn, vp, vn, up + vn, un - vn); else ref_mpn_mul (wp + vn, up + vn, un - vn, vp, vn); MPN_COPY (wp, tp, vn); cy = mpn_add_n (wp + vn, wp + vn, tp + vn, vn); mpn_incr_u (wp + 2 * vn, cy); } else { MPN_COPY (wp, tp, 2 * vn); } __GMP_FREE_FUNC_LIMBS (tp, tn);}static voidmul_basecase (mp_ptr wp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn){ mp_size_t i, j; mp_limb_t prod_low, prod_high; mp_limb_t cy_dig; mp_limb_t v_limb; /* Multiply by the first limb in V separately, as the result can be stored (not added) to PROD. We also avoid a loop for zeroing. */ v_limb = vp[0]; cy_dig = 0; for (j = un; j > 0; j--) { mp_limb_t u_limb, w_limb; u_limb = *up++; umul_ppmm (prod_high, prod_low, u_limb, v_limb << GMP_NAIL_BITS); add_ssaaaa (cy_dig, w_limb, prod_high, prod_low, 0, cy_dig << GMP_NAIL_BITS); *wp++ = w_limb >> GMP_NAIL_BITS; } *wp++ = cy_dig; wp -= un; up -= un; /* For each iteration in the outer loop, multiply one limb from U with one limb from V, and add it to PROD. */ for (i = 1; i < vn; i++) { v_limb = vp[i]; cy_dig = 0; for (j = un; j > 0; j--) { mp_limb_t u_limb, w_limb; u_limb = *up++; umul_ppmm (prod_high, prod_low, u_limb, v_limb << GMP_NAIL_BITS); w_limb = *wp; add_ssaaaa (prod_high, prod_low, prod_high, prod_low, 0, w_limb << GMP_NAIL_BITS); prod_low >>= GMP_NAIL_BITS; prod_low += cy_dig;#if GMP_NAIL_BITS == 0 cy_dig = prod_high + (prod_low < cy_dig);#else cy_dig = prod_high; cy_dig += prod_low >> GMP_NUMB_BITS;#endif *wp++ = prod_low & GMP_NUMB_MASK; } *wp++ = cy_dig; wp -= un; up -= un; }}voiddump_abort (int i, char *s, mpz_t op1, mpz_t op2, mpz_t product, mpz_t ref_product){ fprintf (stderr, "ERROR: %s in test %d\n", s, i); fprintf (stderr, "op1 = "); debug_mp (op1); fprintf (stderr, "op2 = "); debug_mp (op2); fprintf (stderr, " product = "); debug_mp (product); fprintf (stderr, "ref_product = "); debug_mp (ref_product); abort();}voiddebug_mp (mpz_t x){ size_t siz = mpz_sizeinbase (x, 16); if (siz > 65) { mpz_t q; mpz_init (q); mpz_tdiv_q_2exp (q, x, 4 * (mpz_sizeinbase (x, 16) - 25)); gmp_fprintf (stderr, "%ZX...", q); mpz_tdiv_r_2exp (q, x, 4 * 25); gmp_fprintf (stderr, "%025ZX [%d]\n", q, (int) siz); mpz_clear (q); } else { gmp_fprintf (stderr, "%ZX\n", x); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -