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_CONVERT_HPP 00021 #define BOOST_INCLUDED_XINT_CONVERT_HPP 00022 00024 namespace boost { 00025 namespace xint { 00026 namespace detail { 00027 00028 inline char nToChar(int n, bool upperCase) { 00029 if (n < 10) return char(n + '0'); 00030 else if (upperCase) return char((n - 10) + 'A'); 00031 else return char((n - 10) + 'a'); 00032 } 00033 00034 template <typename charT, bitsize_t Bits, bool Secure, class Alloc> 00035 std::basic_string<charT> to_string(const BOOST_XINT_RAWINT n, std::size_t base = 00036 10, bool uppercase = false) 00037 { 00038 if (base < 2 || base > 36) exception_handler<>::call(__FILE__, __LINE__, 00039 exceptions::invalid_base()); 00040 00041 std::basic_ostringstream<charT> out; 00042 if (n.is_zero()) { 00043 out << "0"; 00044 return out.str(); 00045 } 00046 00047 if (base == 2 || base == 4 || base == 16) { 00048 // Fast no-division version, useful for debugging division and for cases 00049 // where maximum speed is necessary. 00050 const digit_t *firstDigit = n.digits(), *lastDigit = firstDigit + 00051 n.length - 1; 00052 00053 if (n.negative) out << '-'; 00054 00055 int bits_per_base_b_digit = 0; 00056 while (base > 1) { base = base >> 1; ++bits_per_base_b_digit; } 00057 const digit_t mask = (doubledigit_t(1) << bits_per_base_b_digit) - 1; 00058 00059 // Skip any leading zeros 00060 const digit_t *d = lastDigit; 00061 int digitShift = (bits_per_digit - bits_per_base_b_digit); 00062 while (digitShift >= 0 && ((*d >> digitShift) & mask) == 0) 00063 digitShift -= bits_per_base_b_digit; 00064 00065 do { 00066 while (digitShift >= 0) { 00067 out << nToChar((*d >> digitShift) & mask, uppercase); 00068 digitShift -= bits_per_base_b_digit; 00069 } 00070 00071 digitShift = (bits_per_digit - bits_per_base_b_digit); 00072 } while (d-- != firstDigit); 00073 00074 return out.str(); 00075 } else { 00076 // ATTN: for when there's nothing more pressing to do 00077 // This could be made a lot more efficient for very large numbers, by 00078 // dividing n by base raised to whatever number of digits will fit into 00079 // a doubledigit_t, then just doing single-digit divides for that many 00080 // digits before going back to n for another chunk. That would be 00081 // premature optimization though, so I'm just making this note instead. 00082 // If someone can show me a use-case where more efficiency is needed in 00083 // this function, I'll add it later. 00084 00085 BOOST_XINT_RAWINT shift; 00086 shift.set_unsigned(base); 00087 typename BOOST_XINT_RAWINT::divide_t a(divide(n.abs(), shift)); 00088 do { 00089 out << nToChar(a.remainder[0], uppercase); 00090 a = divide(a.quotient, shift); 00091 } while (!a.quotient.is_zero()); 00092 if (!a.remainder.is_zero()) out << nToChar(a.remainder[0], uppercase); 00093 00094 if (n.negative) out << '-'; 00095 00096 std::basic_string<charT> rval = out.str(); 00097 std::reverse(rval.begin(), rval.end()); 00098 return rval; 00099 } 00100 } 00101 00102 BOOST_XINT_RAWINT_TPL 00103 template <typename charT> 00104 void BOOST_XINT_RAWINT::from_string(const charT *str, const charT*& endptr, 00105 std::size_t base) 00106 { 00107 bool negate = false; 00108 const charT *c = str; 00109 while (isspace(*c)) ++c; 00110 00111 if (*c == '+') ++c; 00112 else if (*c == '-') { negate = true; ++c; } 00113 00114 if (base == autobase) { 00115 if (*c == '0') { 00116 ++c; 00117 if (*c == 'x' || *c == 'X') { 00118 ++c; 00119 base = 16; 00120 } else base = 8; 00121 } else base = 10; 00122 } 00123 00124 if (base < 2 || base > 36) exception_handler<>::call(__FILE__, __LINE__, 00125 exceptions::invalid_base()); 00126 if (*c == 0) exception_handler<>::call(__FILE__, __LINE__, 00127 exceptions::invalid_digit("No valid digits")); 00128 00129 std::basic_string<charT> tstr; 00130 if (negate) tstr.push_back('-'); 00131 if (base <= 10) { 00132 const charT p = charT('0' + base); 00133 while (*c >= '0' && *c < p) 00134 tstr.push_back(*c++); 00135 } else { 00136 const charT lower = charT('a' + base - 10), upper = charT('A' + base - 00137 10); 00138 while ((*c >= '0' && *c <= '9') 00139 || (*c >= 'a' && *c < lower) 00140 || (*c >= 'A' && *c < upper)) 00141 tstr.push_back(*c++); 00142 } 00143 endptr = c; 00144 00145 from_string(tstr, base); 00146 } 00147 00148 BOOST_XINT_RAWINT_TPL 00149 template <typename charT> 00150 void BOOST_XINT_RAWINT::from_string(const charT *str, std::size_t base) { 00151 bool negate = false; 00152 const charT *c = str; 00153 if (*c == '+') ++c; 00154 else if (*c == '-') { negate = true; ++c; } 00155 00156 if (base == autobase) { 00157 if (*c == '0') { 00158 ++c; 00159 if (*c == 'x' || *c == 'X') { 00160 ++c; 00161 base = 16; 00162 } else base = 8; 00163 } else base = 10; 00164 } 00165 00166 if (base < 2 || base > 36) exception_handler<>::call(__FILE__, __LINE__, 00167 exceptions::invalid_base()); 00168 if (*c == 0) exception_handler<>::call(__FILE__, __LINE__, 00169 exceptions::invalid_digit("No valid digits")); 00170 00171 // ATTN: for when there's nothing more pressing to do 00172 // This function could use the same efficiency improvements that to_string 00173 // uses, but there's even less need for them here. Show me a use-case where 00174 // they're needed and I'll add them; until then, this will suffice. 00175 00176 BOOST_XINT_RAWINT shift, digit; 00177 shift.set_unsigned(base); 00178 00179 set(0); 00180 while (*c) { 00181 if (*c >= '0' && *c <= '9') digit.set(*c - '0'); 00182 else if (*c >= 'A' && *c <= 'Z') digit.set(*c - 'A' + 10); 00183 else if (*c >= 'a' && *c <= 'z') digit.set(*c - 'a' + 10); 00184 else exception_handler<>::call(__FILE__, __LINE__, 00185 exceptions::invalid_digit("encountered non-alphanumeric character " 00186 "in string")); 00187 00188 if (digit >= shift) exception_handler<>::call(__FILE__, __LINE__, 00189 exceptions::invalid_digit("encountered digit greater than base " 00190 "allows")); 00191 00192 *this *= shift; 00193 *this += digit; 00194 ++c; 00195 } 00196 00197 negative = negate; 00198 trim(); 00199 } 00200 00201 BOOST_XINT_RAWINT_TPL 00202 template <typename charT, typename traitsT, typename allocT> 00203 void BOOST_XINT_RAWINT::from_string(const std::basic_string<charT, traitsT, 00204 allocT>& str, std::size_t base) 00205 { 00206 from_string(str.c_str(), base); 00207 } 00208 00209 BOOST_XINT_RAWINT_TPL 00210 xint::binary_t to_binary(const BOOST_XINT_RAWINT n, std::size_t bits = 0) { 00211 if (bits > std::size_t(std::numeric_limits<unsigned char>::digits)) 00212 exception_handler<>::call(__FILE__, __LINE__, 00213 exceptions::invalid_argument("can't fit that many bits into an " 00214 "unsigned character on this system")); 00215 if (bits == 0) bits = std::numeric_limits<unsigned char>::digits; 00216 00217 bitqueue_t bitqueue; 00218 const digit_t *s = n.digits(), *se = s + n.length; 00219 while (s != se) bitqueue.push(*s++, bits_per_digit); 00220 00221 xint::binary_t target; 00222 while (!bitqueue.empty()) target.push_back(static_cast<unsigned char> 00223 (bitqueue.pop(bits))); 00224 while (!target.empty() && target.back()==0) target.pop_back(); 00225 return target; 00226 } 00227 00228 BOOST_XINT_RAWINT_TPL 00229 void BOOST_XINT_RAWINT::from_binary(xint::binary_t b, std::size_t bits) { 00230 if (bits > std::size_t(std::numeric_limits<unsigned char>::digits)) 00231 exception_handler<>::call(__FILE__, __LINE__, 00232 exceptions::invalid_argument("can't fit that many bits into an " 00233 "unsigned character on this system")); 00234 if (bits == 0) bits = std::numeric_limits<unsigned char>::digits; 00235 00236 bitqueue_t bitqueue; 00237 for (xint::binary_t::const_iterator s = b.begin(), se = b.end(); s != se; 00238 ++s) bitqueue.push(*s, bits); 00239 00240 digit_t *d = digits(bits_to_digits(b.size() * bits), realloc::ignore), *t = 00241 d, *te = t + max_length(); 00242 while (t != te && !bitqueue.empty()) 00243 *t++ = static_cast<digit_t>(bitqueue.pop(bits_per_digit)); 00244 length = (t - d); 00245 trim(); 00246 } 00247 00248 template <typename T, bitsize_t Bits, bool Secure, class Alloc> 00249 T to(const BOOST_XINT_RAWINT n, typename boost::enable_if<boost::is_integral<T> 00250 >::type* = 0) 00251 { 00252 using std::numeric_limits; 00253 00254 static const BOOST_XINT_RAWINT tmin((numeric_limits<T>::min)()); 00255 static const BOOST_XINT_RAWINT tmax((numeric_limits<T>::max)()); 00256 if (n < tmin || n > tmax) exception_handler<>::call(__FILE__, __LINE__, 00257 exceptions::too_big("value out of range for requested conversion")); 00258 00259 // Workaround for MSVC8's C4309 warning, "truncation of constant value" 00260 doubledigit_t shift_tmp = digit_overflowbit; 00261 T rval = 0, shift = T(shift_tmp); 00262 for (std::size_t x = 0; x < n.length; ++x) { 00263 if (sizeof(T) > sizeof(digit_t)) rval *= shift; 00264 rval += static_cast<T>(n[n.length - x - 1]); 00265 } 00266 if (n.negative) rval *= static_cast<T>(-1); 00267 return rval; 00268 } 00269 00270 } // namespace detail 00271 } // namespace xint 00272 } // namespace boost 00274 00275 #endif // BOOST_INCLUDED_XINT_CONVERT_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)