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 00020 #ifndef BOOST_INCLUDED_XINT_ADDSUBTRACT_HPP 00021 #define BOOST_INCLUDED_XINT_ADDSUBTRACT_HPP 00022 00024 namespace boost { 00025 namespace xint { 00026 namespace detail { 00027 00028 BOOST_XINT_RAWINT_TPL 00029 void sub_increment(BOOST_XINT_RAWINT& n, bool absolute_value = false); 00030 BOOST_XINT_RAWINT_TPL 00031 void sub_decrement(BOOST_XINT_RAWINT& n, bool absolute_value = false); 00032 00033 BOOST_XINT_RAWINT_TPL 00034 void sub_add(BOOST_XINT_RAWINT& n, const BOOST_XINT_RAWINT n2) { 00035 digit_t *ndig = n.digits((std::max)(n.length, n2.length) + 1, 00036 realloc::extend), *t = ndig, *te = t + n.length; 00037 const digit_t *p = n2.digits(), *pe = p + (std::min)(n2.length, n.length); 00038 00039 digit_t carry = 0; 00040 while (p != pe) { 00041 doubledigit_t tmp = doubledigit_t(*t) + *p++ + carry; 00042 if (tmp >= digit_overflowbit) { 00043 carry = 1; 00044 *t++ = static_cast<digit_t>(tmp - digit_overflowbit); 00045 } else { 00046 carry = 0; 00047 *t++ = static_cast<digit_t>(tmp); 00048 } 00049 } 00050 00051 if (carry) { 00052 while (t != te) { 00053 if (*t == digit_mask) *t++ = 0; 00054 else { *t++ += 1; break; } 00055 } 00056 } 00057 00058 n.length = (std::max)(n.length, std::size_t(t - ndig)); 00059 n.trim(); 00060 } 00061 00062 BOOST_XINT_RAWINT_TPL 00063 void sub_subtract(BOOST_XINT_RAWINT& n, const BOOST_XINT_RAWINT n2) { 00064 bool swap = (compare(n, n2, true) < 0); 00065 00066 digit_t *ndig = n.digits((std::max)(n.length, n2.length), realloc::extend), 00067 *t = ndig, *te = t + n.length; 00068 const digit_t *p = n2.digits(), *pe = p + (std::min)(n2.length, n.length); 00069 00070 // Now subtract the digits, starting at the least-significant one. 00071 digit_t borrow = 0; 00072 if (swap) { 00073 // abs(n2) is greater than abs(n). Requires slightly different handling. 00074 while (p != pe) { 00075 doubledigit_t tmp = digit_overflowbit + *p++ - *t - borrow; 00076 if (tmp < digit_overflowbit) { 00077 borrow = 1; 00078 *t++ = static_cast<digit_t>(tmp); 00079 } else { 00080 borrow = 0; 00081 *t++ = static_cast<digit_t>(tmp - digit_overflowbit); 00082 } 00083 } 00084 00085 n.length = std::size_t(t - ndig); 00086 n.negative = !n.negative; 00087 } else { 00088 while (p != pe) { 00089 doubledigit_t tmp = digit_overflowbit + *t - *p++ - borrow; 00090 if (tmp < digit_overflowbit) { 00091 borrow = 1; 00092 *t++ = static_cast<digit_t>(tmp); 00093 } else { 00094 borrow = 0; 00095 *t++ = static_cast<digit_t>(tmp - digit_overflowbit); 00096 } 00097 } 00098 00099 if (borrow) { 00100 while (t != te) { 00101 if (*t == 0) *t++ = digit_mask; 00102 else { *t++ -= 1; borrow = 0; break; } 00103 } 00104 } 00105 n.length = (std::max)(n.length, std::size_t(t - ndig)); 00106 } 00107 00108 assert(borrow == 0); 00109 n.trim(); 00110 } 00111 00112 BOOST_XINT_RAWINT_TPL 00113 void sub_increment(BOOST_XINT_RAWINT& n, bool absolute_value) { 00114 if (n.is_zero()) { 00115 n.set(1); 00116 } else if (!absolute_value && n.negative) { 00117 sub_decrement(n, true); 00118 } else { 00119 std::size_t overflow = (n.digits()[n.length - 1] == digit_mask ? 1 : 0); 00120 digit_t *d = n.digits(n.length + overflow, realloc::extend), *p = d, *pe 00121 = p + n.length; 00122 while (p < pe) { 00123 if (*p == digit_mask) *p++ = 0; 00124 else { *p++ += 1; break; } 00125 } 00126 n.trim(); 00127 } 00128 } 00129 00130 BOOST_XINT_RAWINT_TPL 00131 void sub_decrement(BOOST_XINT_RAWINT& n, bool absolute_value) { 00132 if (n.is_zero()) { 00133 n.set(-1); 00134 } else if (!absolute_value && n.negative) { 00135 sub_increment(n, true); 00136 } else { 00137 digit_t *p = n.digits(0), *pe = p + n.length; 00138 00139 while (p < pe) { 00140 if (*p == 0) *p++ = digit_mask; 00141 else { *p++ -= 1; break; } 00142 } 00143 n.trim(); 00144 } 00145 } 00146 00147 BOOST_XINT_RAWINT_TPL 00148 BOOST_XINT_RAWINT& BOOST_XINT_RAWINT::operator++() { 00149 sub_increment(*this); 00150 return *this; 00151 } 00152 00153 BOOST_XINT_RAWINT_TPL 00154 BOOST_XINT_RAWINT& BOOST_XINT_RAWINT::operator--() { 00155 sub_decrement(*this); 00156 return *this; 00157 } 00158 00159 BOOST_XINT_RAWINT_TPL 00160 BOOST_XINT_RAWINT BOOST_XINT_RAWINT::operator++(int) { 00161 BOOST_XINT_RAWINT r(*this); 00162 sub_increment(*this); 00163 return r; 00164 } 00165 00166 BOOST_XINT_RAWINT_TPL 00167 BOOST_XINT_RAWINT BOOST_XINT_RAWINT::operator--(int) { 00168 BOOST_XINT_RAWINT r(*this); 00169 sub_decrement(*this); 00170 return r; 00171 } 00172 00173 BOOST_XINT_RAWINT_TPL 00174 BOOST_XINT_RAWINT& BOOST_XINT_RAWINT::operator+=(const BOOST_XINT_RAWINT n) { 00175 if (!n.is_zero()) { 00176 if (is_zero()) { 00177 *this = n; 00178 } else if (negative != n.negative) { 00179 sub_subtract(*this, n.negate()); 00180 } else { 00181 sub_add(*this, n); 00182 } 00183 } 00184 return *this; 00185 } 00186 00187 BOOST_XINT_RAWINT_TPL 00188 BOOST_XINT_RAWINT& BOOST_XINT_RAWINT::operator-=(const BOOST_XINT_RAWINT n) { 00189 if (!n.is_zero()) { 00190 if (is_zero()) { 00191 *this = n.negate(); 00192 } else if (negative != n.negative) { 00193 sub_add(*this, n.negate()); 00194 } else { 00195 sub_subtract(*this, n); 00196 } 00197 } 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 r(n1); 00206 r+=n2; 00207 return r; 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 r(n1); 00215 r-=n2; 00216 return r; 00217 } 00218 00219 // note: once the test system is up and running, rewrite add/subtract code to write to a separate raw_integer & return it, for greater efficiency. 00220 00221 } // namespace detail 00222 } // namespace xint 00223 } // namespace boost 00225 00226 #endif // BOOST_INCLUDED_XINT_ADDSUBTRACT_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)