toom6h_mul.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:8k
- /* Implementation of the multiplication algorithm for Toom-Cook 6.5-way.
- Contributed to the GNU project by Marco Bodrato.
- THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE. IT IS ONLY
- SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES. IN FACT, IT IS ALMOST
- GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
- Copyright 2009, 2010 Free Software Foundation, Inc.
- This file is part of the GNU MP Library.
- The GNU MP Library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 3 of the License, or (at your
- option) any later version.
- The GNU MP Library is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
- #include "gmp.h"
- #include "gmp-impl.h"
- #if GMP_NUMB_BITS < 21
- #error Not implemented.
- #endif
- #if TUNE_PROGRAM_BUILD
- #define MAYBE_mul_basecase 1
- #define MAYBE_mul_toom22 1
- #define MAYBE_mul_toom33 1
- #define MAYBE_mul_toom6h 1
- #else
- #define MAYBE_mul_basecase
- (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM22_THRESHOLD)
- #define MAYBE_mul_toom22
- (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM33_THRESHOLD)
- #define MAYBE_mul_toom33
- (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM44_THRESHOLD)
- #define MAYBE_mul_toom6h
- (MUL_FFT_THRESHOLD >= 6 * MUL_TOOM6H_THRESHOLD)
- #endif
- #define TOOM6H_MUL_N_REC(p, a, b, n, ws)
- do {
- if (MAYBE_mul_basecase
- && BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
- mpn_mul_basecase (p, a, n, b, n);
- else if (MAYBE_mul_toom22
- && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD))
- mpn_toom22_mul (p, a, n, b, n, ws);
- else if (MAYBE_mul_toom33
- && BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD))
- mpn_toom33_mul (p, a, n, b, n, ws);
- else if (! MAYBE_mul_toom6h
- || BELOW_THRESHOLD (n, MUL_TOOM6H_THRESHOLD))
- mpn_toom44_mul (p, a, n, b, n, ws);
- else
- mpn_toom6h_mul (p, a, n, b, n, ws);
- } while (0)
- #define TOOM6H_MUL_REC(p, a, na, b, nb, ws)
- do { mpn_mul (p, a, na, b, nb);
- } while (0)
- /* Toom-6.5 , compute the product {pp,an+bn} <- {ap,an} * {bp,bn}
- With: an >= bn >= 46, an*6 < bn * 17.
- It _may_ work with bn<=46 and bn*17 < an*6 < bn*18
- Evaluate in: infinity, +4, -4, +2, -2, +1, -1, +1/2, -1/2, +1/4, -1/4, 0.
- */
- /* Estimate on needed scratch:
- S(n) <= (n+5)6*10+4+MAX(S((n+5)6),1+2*(n+5)6),
- since n>42; S(n) <= ceil(log(n)/log(6))*(10+4)+n*126 < n*2 + lg2(n)*6
- */
- void
- mpn_toom6h_mul (mp_ptr pp,
- mp_srcptr ap, mp_size_t an,
- mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
- {
- mp_size_t n, s, t;
- int p, q, half;
- int sign;
- /***************************** decomposition *******************************/
- ASSERT( an >= bn);
- /* Can not handle too much unbalancement */
- ASSERT( bn >= 42 );
- /* Can not handle too much unbalancement */
- ASSERT((an*3 < bn * 8) || ( bn >= 46 && an*6 < bn * 17 ));
- /* Limit num/den is a rational number between
- (12/11)^(log(4)/log(2*4-1)) and (12/11)^(log(6)/log(2*6-1)) */
- #define LIMIT_numerator (18)
- #define LIMIT_denominat (17)
- if( an * LIMIT_denominat < LIMIT_numerator * bn ) /* is 6*... < 6*... */
- { p = q = 6; }
- else if( an * 5 * LIMIT_numerator < LIMIT_denominat * 7 * bn )
- { p = 7; q = 6; }
- else if( an * 5 * LIMIT_denominat < LIMIT_numerator * 7 * bn )
- { p = 7; q = 5; }
- else if( an * LIMIT_numerator < LIMIT_denominat * 2 * bn ) /* is 4*... < 8*... */
- { p = 8; q = 5; }
- else if( an * LIMIT_denominat < LIMIT_numerator * 2 * bn ) /* is 4*... < 8*... */
- { p = 8; q = 4; }
- else
- { p = 9; q = 4; }
- half = (p ^ q) & 1;
- n = 1 + (q * an >= p * bn ? (an - 1) / (size_t) p : (bn - 1) / (size_t) q);
- p--; q--;
- s = an - p * n;
- t = bn - q * n;
- /* With LIMIT = 16/15, the following recover is needed only if bn<=73*/
- if (half) { /* Recover from badly chosen splitting */
- if (s<1) {p--; s+=n; half=0;}
- else if (t<1) {q--; t+=n; half=0;}
- }
- #undef LIMIT_numerator
- #undef LIMIT_denominat
- ASSERT (0 < s && s <= n);
- ASSERT (0 < t && t <= n);
- ASSERT (half || s + t > 3);
- ASSERT (n > 2);
- #define r4 (pp + 3 * n) /* 3n+1 */
- #define r2 (pp + 7 * n) /* 3n+1 */
- #define r0 (pp +11 * n) /* s+t <= 2*n */
- #define r5 (scratch) /* 3n+1 */
- #define r3 (scratch + 3 * n + 1) /* 3n+1 */
- #define r1 (scratch + 6 * n + 2) /* 3n+1 */
- #define v0 (pp + 7 * n) /* n+1 */
- #define v1 (pp + 8 * n+1) /* n+1 */
- #define v2 (pp + 9 * n+2) /* n+1 */
- #define v3 (scratch + 9 * n + 3) /* n+1 */
- #define wsi (scratch + 9 * n + 3) /* 3n+1 */
- #define wse (scratch +10 * n + 4) /* 2n+1 */
- /* Alloc also 3n+1 limbs for wsi... toom_interpolate_12pts may
- need all of them */
- /* if (scratch == NULL) */
- /* scratch = TMP_SALLOC_LIMBS(mpn_toom6_sqr_itch(n * 6)); */
- ASSERT (12 * n + 6 <= mpn_toom6h_mul_itch(an,bn));
- ASSERT (12 * n + 6 <= mpn_toom6_sqr_itch(n * 6));
- /********************** evaluation and recursive calls *********************/
- /* $pm1/2$ */
- sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 1, pp) ^
- mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 1, pp);
- TOOM6H_MUL_N_REC(pp, v0, v1, n + 1, wse); /* A(-1/2)*B(-1/2)*2^. */
- TOOM6H_MUL_N_REC(r5, v2, v3, n + 1, wse); /* A(+1/2)*B(+1/2)*2^. */
- mpn_toom_couple_handling (r5, 2 * n + 1, pp, sign, n, 1+half , half);
- /* $pm1$ */
- sign = mpn_toom_eval_pm1 (v2, v0, p, ap, n, s, pp);
- if (q == 3)
- sign ^= mpn_toom_eval_dgr3_pm1 (v3, v1, bp, n, t, pp);
- else
- sign ^= mpn_toom_eval_pm1 (v3, v1, q, bp, n, t, pp);
- TOOM6H_MUL_N_REC(pp, v0, v1, n + 1, wse); /* A(-1)*B(-1) */
- TOOM6H_MUL_N_REC(r3, v2, v3, n + 1, wse); /* A(1)*B(1) */
- mpn_toom_couple_handling (r3, 2 * n + 1, pp, sign, n, 0, 0);
- /* $pm4$ */
- sign = mpn_toom_eval_pm2exp (v2, v0, p, ap, n, s, 2, pp) ^
- mpn_toom_eval_pm2exp (v3, v1, q, bp, n, t, 2, pp);
- TOOM6H_MUL_N_REC(pp, v0, v1, n + 1, wse); /* A(-4)*B(-4) */
- TOOM6H_MUL_N_REC(r1, v2, v3, n + 1, wse); /* A(+4)*B(+4) */
- mpn_toom_couple_handling (r1, 2 * n + 1, pp, sign, n, 2, 4);
- /* $pm1/4$ */
- sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 2, pp) ^
- mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 2, pp);
- TOOM6H_MUL_N_REC(pp, v0, v1, n + 1, wse); /* A(-1/4)*B(-1/4)*4^. */
- TOOM6H_MUL_N_REC(r4, v2, v3, n + 1, wse); /* A(+1/4)*B(+1/4)*4^. */
- mpn_toom_couple_handling (r4, 2 * n + 1, pp, sign, n, 2*(1+half), 2*(half));
- /* $pm2$ */
- sign = mpn_toom_eval_pm2 (v2, v0, p, ap, n, s, pp) ^
- mpn_toom_eval_pm2 (v3, v1, q, bp, n, t, pp);
- TOOM6H_MUL_N_REC(pp, v0, v1, n + 1, wse); /* A(-2)*B(-2) */
- TOOM6H_MUL_N_REC(r2, v2, v3, n + 1, wse); /* A(+2)*B(+2) */
- mpn_toom_couple_handling (r2, 2 * n + 1, pp, sign, n, 1, 2);
- #undef v0
- #undef v1
- #undef v2
- #undef v3
- #undef wse
- /* A(0)*B(0) */
- TOOM6H_MUL_N_REC(pp, ap, bp, n, wsi);
- /* Infinity */
- if( half != 0) {
- if(s>t) {
- TOOM6H_MUL_REC(r0, ap + p * n, s, bp + q * n, t, wsi);
- } else {
- TOOM6H_MUL_REC(r0, bp + q * n, t, ap + p * n, s, wsi);
- };
- };
- mpn_toom_interpolate_12pts (pp, r1, r3, r5, n, s+t, half, wsi);
- #undef r0
- #undef r1
- #undef r2
- #undef r3
- #undef r4
- #undef r5
- #undef wsi
- }
- #undef TOOM6H_MUL_N_REC
- #undef TOOM6H_MUL_REC
- #undef MAYBE_mul_basecase
- #undef MAYBE_mul_toom22
- #undef MAYBE_mul_toom33
- #undef MAYBE_mul_toom6h