00001 00002 /* 00003 The Extended Integer (XInt) Library 00004 A fast, portable C++ library for multi-precision integer math 00005 Copyright 2010 by Chad Nelson 00006 00007 Distributed under the Boost Software License, Version 1.0. 00008 See accompanying file LICENSE_1_0.txt or copy at 00009 http://www.boost.org/LICENSE_1_0.txt 00010 00011 See http://www.boost.org/libs/xint for library home page. 00012 */ 00013 00021 #ifndef BOOST_INCLUDED_XINT_DIVIDE_HPP 00022 #define BOOST_INCLUDED_XINT_DIVIDE_HPP 00023 00025 namespace boost { 00026 namespace xint { 00027 namespace detail { 00028 00029 BOOST_XINT_RAWINT_TPL 00030 void divide_by_single_digit(BOOST_XINT_RAWINT& qtarget, BOOST_XINT_RAWINT& 00031 rtarget, const BOOST_XINT_RAWINT d1, digit_t d2) 00032 { 00033 std::size_t d1len = d1.length; 00034 const digit_t *d1digits = d1.digits(); 00035 00036 doubledigit_t a = 0; 00037 00038 int m = int(d1len) - 1; 00039 const digit_t *d1p = d1digits + m; 00040 00041 digit_t *qdig = qtarget.digits(m + 1, realloc::zero), *qp = qdig + m, *qe = 00042 qdig + qtarget.max_length(); 00043 int i = m; 00044 for (; qp >= qe && i >= 0; --i, --d1p, --qp) { 00045 a |= *d1p; 00046 a = ((a % d2) << bits_per_digit); 00047 } 00048 for (; i >= 0; --i, --d1p, --qp) { 00049 a |= *d1p; 00050 *qp = static_cast<digit_t>(a / d2); 00051 a = ((a % d2) << bits_per_digit); 00052 } 00053 qtarget.length = (std::min<size_t>)(m + 1, qtarget.max_length()); 00054 qtarget.trim(); 00055 00056 rtarget.digits(1, realloc::ignore)[0] = static_cast<digit_t>(a >> 00057 bits_per_digit); 00058 rtarget.length = 1; 00059 rtarget.trim(); 00060 } 00061 00062 BOOST_XINT_RAWINT_TPL 00063 void sub_divide2(BOOST_XINT_RAWINT& qtarget, BOOST_XINT_RAWINT& rtarget, const 00064 BOOST_XINT_RAWINT d1, const BOOST_XINT_RAWINT d2) 00065 { 00066 typedef raw_integer_t<0, Secure, Alloc> BOOST_XINT_UNLIMITED; 00067 assert(d2[d2.length - 1] >= digit_overflowbit / 2); 00068 00069 const digit_t *byDigits = d2.digits(); 00070 00071 std::size_t n = d2.length, m = d1.length - n; 00072 std::size_t i = m + n, j = m; 00073 00074 digit_t *qdigits = qtarget.digits(j + 1, realloc::ignore); 00075 qtarget.length = (std::min)(j + 1, qtarget.max_length()); 00076 rtarget = d1; 00077 BOOST_XINT_UNLIMITED r2(0, 3), qq; 00078 do { 00079 doubledigit_t ri = (doubledigit_t(rtarget.get_digit(i)) << 00080 bits_per_digit) + rtarget.get_digit(i - 1); 00081 doubledigit_t q = (std::min<doubledigit_t>)(ri / byDigits[n - 1], 00082 digit_mask); 00083 00084 while (1) { 00085 // We need three digits here, a doubledigit_t alone won't suffice. 00086 { 00087 doubledigit_t tmp = ri - (q * byDigits[n - 1]); 00088 digit_t *r2dig = r2.digits(3, realloc::ignore); 00089 *r2dig++ = rtarget[i - 2]; 00090 *r2dig++ = static_cast<digit_t>(tmp & digit_mask); 00091 tmp >>= bits_per_digit; 00092 *r2dig++ = static_cast<digit_t>(tmp); 00093 r2.trim(); 00094 } 00095 00096 qq.set_unsigned(q); 00097 if (BOOST_XINT_UNLIMITED(byDigits[n - 2]) * qq <= r2) break; 00098 --q; 00099 } 00100 00101 BOOST_XINT_RAWINT bq(d2 * BOOST_XINT_RAWINT(q)); 00102 if (rtarget < bq) { 00103 --q; 00104 bq -= d2; 00105 } 00106 00107 bq <<= bits_per_digit * (i - n); 00108 rtarget -= bq; 00109 00110 qdigits[j--] = digit_t(q); 00111 } while (--i >= n); 00112 rtarget.trim(); 00113 qtarget.trim(); 00114 } 00115 00119 BOOST_XINT_RAWINT_TPL 00120 void sub_divide(BOOST_XINT_RAWINT& qtarget, BOOST_XINT_RAWINT& rtarget, const 00121 BOOST_XINT_RAWINT d1, const BOOST_XINT_RAWINT d2) 00122 { 00123 if (d2.length == 1) { 00124 divide_by_single_digit(qtarget, rtarget, d1, d2[0]); 00125 } else { 00126 // The normalization step 00127 digit_t normalizer = static_cast<digit_t>(digit_overflowbit / 00128 (doubledigit_t(d2[d2.length - 1]) + 1)); 00129 if (normalizer > 1) { 00130 const BOOST_XINT_RAWINT norm(normalizer); 00131 sub_divide2(qtarget, rtarget, d1 * norm, d2 * norm); 00132 00133 // Denormalization step. This requires division by a single digit_t. 00134 BOOST_XINT_RAWINT tmp; 00135 divide_by_single_digit(rtarget, tmp, rtarget, normalizer); 00136 } else sub_divide2(qtarget, rtarget, d1, d2); 00137 } 00138 } 00139 00142 BOOST_XINT_RAWINT_TPL 00143 void divide(BOOST_XINT_RAWINT& qtarget, BOOST_XINT_RAWINT& rtarget, const 00144 BOOST_XINT_RAWINT d1, const BOOST_XINT_RAWINT d2) 00145 { 00146 int sign1 = (d1.is_zero() ? 0 : d1.negative ? -1 : 1); 00147 int sign2 = (d2.is_zero() ? 0 : d2.negative ? -1 : 1); 00148 if (sign2 == 0) exception_handler<>::call(__FILE__, __LINE__, 00149 exceptions::divide_by_zero()); 00150 00151 int comp = compare(d1, d2, true); 00152 if (comp < 0) { 00153 qtarget.set(0); 00154 rtarget = d1; 00155 } else if (comp == 0) { 00156 qtarget.set(sign1 != sign2 ? -1 : 1); 00157 rtarget.set(0); 00158 } else if (sign1 < 0 && sign2 < 0) { 00159 sub_divide(qtarget, rtarget, d1.negate(), d2.negate()); 00160 qtarget.negative = false; 00161 rtarget.negative = true; 00162 } else if (sign1 < 0) { 00163 sub_divide(qtarget, rtarget, d1.negate(), d2); 00164 qtarget.negative = rtarget.negative = true; 00165 } else if (sign2 < 0) { 00166 sub_divide(qtarget, rtarget, d1, d2.negate()); 00167 qtarget.negative = true; 00168 rtarget.negative = false; 00169 } else { 00170 sub_divide(qtarget, rtarget, d1, d2); 00171 qtarget.negative = rtarget.negative = false; 00172 } 00173 rtarget.trim(); 00174 qtarget.trim(); 00175 } 00176 00177 BOOST_XINT_RAWINT_TPL 00178 typename BOOST_XINT_RAWINT::divide_t divide(const BOOST_XINT_RAWINT d1, const 00179 BOOST_XINT_RAWINT d2) 00180 { 00181 BOOST_XINT_RAWINT q, r; 00182 divide(q, r, d1, d2); 00183 return typename BOOST_XINT_RAWINT::divide_t(q, r); 00184 } 00185 00186 BOOST_XINT_RAWINT_TPL 00187 BOOST_XINT_RAWINT& BOOST_XINT_RAWINT::operator/=(const BOOST_XINT_RAWINT b) { 00188 BOOST_XINT_RAWINT remainder; 00189 divide(*this, remainder, *this, b); 00190 return *this; 00191 } 00192 00193 BOOST_XINT_RAWINT_TPL 00194 BOOST_XINT_RAWINT& BOOST_XINT_RAWINT::operator%=(const BOOST_XINT_RAWINT b) { 00195 BOOST_XINT_RAWINT quotient; 00196 divide(quotient, *this, *this, b); 00197 if (negative) *this += b.abs(); 00198 return *this; 00199 } 00200 00201 BOOST_XINT_RAWINT_TPL 00202 BOOST_XINT_RAWINT operator/(const BOOST_XINT_RAWINT n1, const BOOST_XINT_RAWINT 00203 n2) 00204 { 00205 BOOST_XINT_RAWINT quotient, remainder; 00206 divide(quotient, remainder, n1, n2); 00207 return quotient; 00208 } 00209 00210 BOOST_XINT_RAWINT_TPL 00211 BOOST_XINT_RAWINT operator%(const BOOST_XINT_RAWINT n1, const BOOST_XINT_RAWINT 00212 n2) 00213 { 00214 BOOST_XINT_RAWINT quotient, remainder; 00215 divide(quotient, remainder, n1, n2); 00216 if (remainder.negative) remainder += n2.abs(); 00217 return remainder; 00218 } 00219 00220 } // namespace detail 00221 } // namespace xint 00222 } // namespace boost 00224 00225 #endif // BOOST_INCLUDED_XINT_DIVIDE_HPP
© Copyright Chad Nelson, 2010-2011. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)