1 1.1 mrg /* mpn_mu_div_q. 2 1.1 mrg 3 1.1 mrg Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato. 4 1.1 mrg 5 1.1 mrg THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES. IT IS ONLY 6 1.1 mrg SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES. IN FACT, IT IS ALMOST 7 1.1 mrg GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE. 8 1.1 mrg 9 1.1.1.2 mrg Copyright 2005-2007, 2009, 2010, 2013 Free Software Foundation, Inc. 10 1.1 mrg 11 1.1 mrg This file is part of the GNU MP Library. 12 1.1 mrg 13 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify 14 1.1.1.2 mrg it under the terms of either: 15 1.1.1.2 mrg 16 1.1.1.2 mrg * the GNU Lesser General Public License as published by the Free 17 1.1.1.2 mrg Software Foundation; either version 3 of the License, or (at your 18 1.1.1.2 mrg option) any later version. 19 1.1.1.2 mrg 20 1.1.1.2 mrg or 21 1.1.1.2 mrg 22 1.1.1.2 mrg * the GNU General Public License as published by the Free Software 23 1.1.1.2 mrg Foundation; either version 2 of the License, or (at your option) any 24 1.1.1.2 mrg later version. 25 1.1.1.2 mrg 26 1.1.1.2 mrg or both in parallel, as here. 27 1.1 mrg 28 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but 29 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 30 1.1.1.2 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 31 1.1.1.2 mrg for more details. 32 1.1 mrg 33 1.1.1.2 mrg You should have received copies of the GNU General Public License and the 34 1.1.1.2 mrg GNU Lesser General Public License along with the GNU MP Library. If not, 35 1.1.1.2 mrg see https://www.gnu.org/licenses/. */ 36 1.1 mrg 37 1.1 mrg 38 1.1 mrg /* 39 1.1 mrg The idea of the algorithm used herein is to compute a smaller inverted value 40 1.1 mrg than used in the standard Barrett algorithm, and thus save time in the 41 1.1 mrg Newton iterations, and pay just a small price when using the inverted value 42 1.1 mrg for developing quotient bits. This algorithm was presented at ICMS 2006. 43 1.1 mrg */ 44 1.1 mrg 45 1.1 mrg /* 46 1.1 mrg Things to work on: 47 1.1 mrg 48 1.1 mrg 1. This is a rudimentary implementation of mpn_mu_div_q. The algorithm is 49 1.1 mrg probably close to optimal, except when mpn_mu_divappr_q fails. 50 1.1 mrg 51 1.1 mrg 2. We used to fall back to mpn_mu_div_qr when we detect a possible 52 1.1 mrg mpn_mu_divappr_q rounding problem, now we multiply and compare. 53 1.1 mrg Unfortunately, since mpn_mu_divappr_q does not return the partial 54 1.1 mrg remainder, this also doesn't become optimal. A mpn_mu_divappr_qr could 55 1.1 mrg solve that. 56 1.1 mrg 57 1.1 mrg 3. The allocations done here should be made from the scratch area, which 58 1.1 mrg then would need to be amended. 59 1.1 mrg */ 60 1.1 mrg 61 1.1 mrg #include <stdlib.h> /* for NULL */ 62 1.1 mrg #include "gmp-impl.h" 63 1.1 mrg 64 1.1 mrg 65 1.1 mrg mp_limb_t 66 1.1 mrg mpn_mu_div_q (mp_ptr qp, 67 1.1 mrg mp_srcptr np, mp_size_t nn, 68 1.1 mrg mp_srcptr dp, mp_size_t dn, 69 1.1 mrg mp_ptr scratch) 70 1.1 mrg { 71 1.1.1.2 mrg mp_ptr tp, rp; 72 1.1.1.2 mrg mp_size_t qn; 73 1.1 mrg mp_limb_t cy, qh; 74 1.1 mrg TMP_DECL; 75 1.1 mrg 76 1.1 mrg TMP_MARK; 77 1.1 mrg 78 1.1 mrg qn = nn - dn; 79 1.1 mrg 80 1.1 mrg tp = TMP_BALLOC_LIMBS (qn + 1); 81 1.1 mrg 82 1.1 mrg if (qn >= dn) /* nn >= 2*dn + 1 */ 83 1.1 mrg { 84 1.1 mrg /* |_______________________| dividend 85 1.1 mrg |________| divisor */ 86 1.1 mrg 87 1.1.1.2 mrg rp = TMP_BALLOC_LIMBS (nn + 1); 88 1.1.1.2 mrg MPN_COPY (rp + 1, np, nn); 89 1.1 mrg rp[0] = 0; 90 1.1.1.2 mrg 91 1.1.1.2 mrg qh = mpn_cmp (rp + 1 + nn - dn, dp, dn) >= 0; 92 1.1.1.2 mrg if (qh != 0) 93 1.1.1.2 mrg mpn_sub_n (rp + 1 + nn - dn, rp + 1 + nn - dn, dp, dn); 94 1.1.1.2 mrg 95 1.1.1.2 mrg cy = mpn_mu_divappr_q (tp, rp, nn + 1, dp, dn, scratch); 96 1.1 mrg 97 1.1 mrg if (UNLIKELY (cy != 0)) 98 1.1 mrg { 99 1.1 mrg /* Since the partial remainder fed to mpn_preinv_mu_divappr_q was 100 1.1 mrg canonically reduced, replace the returned value of B^(qn-dn)+eps 101 1.1 mrg by the largest possible value. */ 102 1.1 mrg mp_size_t i; 103 1.1.1.2 mrg for (i = 0; i < qn + 1; i++) 104 1.1 mrg tp[i] = GMP_NUMB_MAX; 105 1.1 mrg } 106 1.1 mrg 107 1.1 mrg /* The max error of mpn_mu_divappr_q is +4. If the low quotient limb is 108 1.1.1.2 mrg smaller than the max error, we cannot trust the quotient. */ 109 1.1 mrg if (tp[0] > 4) 110 1.1 mrg { 111 1.1 mrg MPN_COPY (qp, tp + 1, qn); 112 1.1 mrg } 113 1.1 mrg else 114 1.1 mrg { 115 1.1 mrg mp_limb_t cy; 116 1.1 mrg mp_ptr pp; 117 1.1 mrg 118 1.1.1.2 mrg pp = rp; 119 1.1 mrg mpn_mul (pp, tp + 1, qn, dp, dn); 120 1.1 mrg 121 1.1 mrg cy = (qh != 0) ? mpn_add_n (pp + qn, pp + qn, dp, dn) : 0; 122 1.1 mrg 123 1.1 mrg if (cy || mpn_cmp (pp, np, nn) > 0) /* At most is wrong by one, no cycle. */ 124 1.1 mrg qh -= mpn_sub_1 (qp, tp + 1, qn, 1); 125 1.1 mrg else /* Same as above */ 126 1.1 mrg MPN_COPY (qp, tp + 1, qn); 127 1.1 mrg } 128 1.1 mrg } 129 1.1 mrg else 130 1.1 mrg { 131 1.1 mrg /* |_______________________| dividend 132 1.1 mrg |________________| divisor */ 133 1.1 mrg 134 1.1 mrg /* FIXME: When nn = 2dn-1, qn becomes dn-1, and the numerator size passed 135 1.1 mrg here becomes 2dn, i.e., more than nn. This shouldn't hurt, since only 136 1.1 mrg the most significant dn-1 limbs will actually be read, but it is not 137 1.1 mrg pretty. */ 138 1.1 mrg 139 1.1 mrg qh = mpn_mu_divappr_q (tp, np + nn - (2 * qn + 2), 2 * qn + 2, 140 1.1 mrg dp + dn - (qn + 1), qn + 1, scratch); 141 1.1 mrg 142 1.1 mrg /* The max error of mpn_mu_divappr_q is +4, but we get an additional 143 1.1 mrg error from the divisor truncation. */ 144 1.1 mrg if (tp[0] > 6) 145 1.1 mrg { 146 1.1 mrg MPN_COPY (qp, tp + 1, qn); 147 1.1 mrg } 148 1.1 mrg else 149 1.1 mrg { 150 1.1 mrg mp_limb_t cy; 151 1.1 mrg 152 1.1 mrg /* FIXME: a shorter product should be enough; we may use already 153 1.1 mrg allocated space... */ 154 1.1 mrg rp = TMP_BALLOC_LIMBS (nn); 155 1.1 mrg mpn_mul (rp, dp, dn, tp + 1, qn); 156 1.1 mrg 157 1.1 mrg cy = (qh != 0) ? mpn_add_n (rp + qn, rp + qn, dp, dn) : 0; 158 1.1 mrg 159 1.1 mrg if (cy || mpn_cmp (rp, np, nn) > 0) /* At most is wrong by one, no cycle. */ 160 1.1 mrg qh -= mpn_sub_1 (qp, tp + 1, qn, 1); 161 1.1 mrg else /* Same as above */ 162 1.1 mrg MPN_COPY (qp, tp + 1, qn); 163 1.1 mrg } 164 1.1 mrg } 165 1.1 mrg 166 1.1 mrg TMP_FREE; 167 1.1 mrg return qh; 168 1.1 mrg } 169 1.1 mrg 170 1.1 mrg mp_size_t 171 1.1 mrg mpn_mu_div_q_itch (mp_size_t nn, mp_size_t dn, int mua_k) 172 1.1 mrg { 173 1.1.1.2 mrg mp_size_t qn; 174 1.1 mrg 175 1.1 mrg qn = nn - dn; 176 1.1 mrg if (qn >= dn) 177 1.1 mrg { 178 1.1.1.2 mrg return mpn_mu_divappr_q_itch (nn + 1, dn, mua_k); 179 1.1 mrg } 180 1.1 mrg else 181 1.1 mrg { 182 1.1.1.2 mrg return mpn_mu_divappr_q_itch (2 * qn + 2, qn + 1, mua_k); 183 1.1 mrg } 184 1.1 mrg } 185