File indexing completed on 2025-01-18 09:42:21
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_MP_FLOAT_STRING_CVT_HPP
0013 #define BOOST_MP_FLOAT_STRING_CVT_HPP
0014
0015 #include <string>
0016 #include <cctype>
0017 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0018 #include <boost/multiprecision/detail/assert.hpp>
0019
0020 namespace boost { namespace multiprecision { namespace detail {
0021
0022 template <class I>
0023 inline void round_string_up_at(std::string& s, std::ptrdiff_t pos, I& expon)
0024 {
0025
0026
0027
0028 if (pos < 0)
0029 {
0030 s.insert(static_cast<std::string::size_type>(0), 1, '1');
0031 s.erase(s.size() - 1);
0032 ++expon;
0033 }
0034 else if (s[static_cast<std::size_t>(pos)] == '9')
0035 {
0036 s[static_cast<std::size_t>(pos)] = '0';
0037 round_string_up_at(s, pos - 1, expon);
0038 }
0039 else
0040 {
0041 if ((pos == 0) && (s[static_cast<std::size_t>(pos)] == '0') && (s.size() == 1))
0042 ++expon;
0043 ++s[static_cast<std::size_t>(pos)];
0044 }
0045 }
0046
0047 template <class Backend>
0048 std::string convert_to_string(Backend b, std::streamsize digits, std::ios_base::fmtflags f)
0049 {
0050 using default_ops::eval_convert_to;
0051 using default_ops::eval_divide;
0052 using default_ops::eval_floor;
0053 using default_ops::eval_fpclassify;
0054 using default_ops::eval_log10;
0055 using default_ops::eval_multiply;
0056 using default_ops::eval_pow;
0057 using default_ops::eval_subtract;
0058
0059 using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
0060 using exponent_type = typename Backend::exponent_type ;
0061
0062 std::string result;
0063 bool iszero = false;
0064 bool isneg = false;
0065 exponent_type expon = 0;
0066 std::streamsize org_digits = digits;
0067 BOOST_MP_ASSERT(digits > 0);
0068
0069 int fpt = eval_fpclassify(b);
0070
0071 if (fpt == static_cast<int>(FP_ZERO))
0072 {
0073 result = "0";
0074 iszero = true;
0075 }
0076 else if (fpt == static_cast<int>(FP_INFINITE))
0077 {
0078 if (b.compare(ui_type(0)) < 0)
0079 return "-inf";
0080 else
0081 return ((f & std::ios_base::showpos) == std::ios_base::showpos) ? "+inf" : "inf";
0082 }
0083 else if (fpt == static_cast<int>(FP_NAN))
0084 {
0085 return "nan";
0086 }
0087 else
0088 {
0089
0090
0091
0092 isneg = b.compare(ui_type(0)) < 0;
0093 if (isneg)
0094 b.negate();
0095 Backend t;
0096 Backend ten;
0097 ten = ui_type(10);
0098
0099 eval_log10(t, b);
0100 eval_floor(t, t);
0101 eval_convert_to(&expon, t);
0102 if (-expon > std::numeric_limits<number<Backend> >::max_exponent10 - 3)
0103 {
0104 int e = -expon / 2;
0105 Backend t2;
0106 eval_pow(t2, ten, e);
0107 eval_multiply(t, t2, b);
0108 eval_multiply(t, t2);
0109 if (expon & 1)
0110 eval_multiply(t, ten);
0111 }
0112 else
0113 {
0114 eval_pow(t, ten, -expon);
0115 eval_multiply(t, b);
0116 }
0117
0118
0119
0120 if (t.compare(ui_type(1)) < 0)
0121 {
0122 eval_multiply(t, ui_type(10));
0123 --expon;
0124 }
0125 else if (t.compare(ui_type(10)) >= 0)
0126 {
0127 eval_divide(t, ui_type(10));
0128 ++expon;
0129 }
0130 Backend digit;
0131 ui_type cdigit;
0132
0133
0134
0135 if (((f & std::ios_base::fixed) == std::ios_base::fixed) && (expon != -1))
0136 digits += expon + 1;
0137 if ((f & std::ios_base::scientific) == std::ios_base::scientific)
0138 ++digits;
0139
0140
0141
0142 for (unsigned i = 0; i < digits; ++i)
0143 {
0144 eval_floor(digit, t);
0145 eval_convert_to(&cdigit, digit);
0146 result += static_cast<char>('0' + cdigit);
0147 eval_subtract(t, digit);
0148 eval_multiply(t, ten);
0149 }
0150
0151
0152
0153 if (digits >= 0)
0154 {
0155 eval_floor(digit, t);
0156 eval_convert_to(&cdigit, digit);
0157 eval_subtract(t, digit);
0158 if ((cdigit == 5) && (t.compare(ui_type(0)) == 0))
0159 {
0160
0161 if ((*result.rbegin() - '0') & 1)
0162 {
0163 round_string_up_at(result, static_cast<std::ptrdiff_t>(result.size() - 1u), expon);
0164 }
0165 }
0166 else if (cdigit >= 5)
0167 {
0168 round_string_up_at(result, static_cast<std::ptrdiff_t>(result.size() - 1u), expon);
0169 }
0170 }
0171 eval_floor(t, b);
0172 if ((t.compare(b) == 0) && (static_cast<std::size_t>(expon + 1) < result.size()))
0173 {
0174
0175
0176 round_string_up_at(result, expon + 1, expon);
0177 result.erase(static_cast<std::string::size_type>(expon + 1));
0178 }
0179 }
0180 while ((static_cast<std::streamsize>(result.size()) > digits) && (result.size() != 0U))
0181 {
0182
0183 if (result.size() > 1)
0184 result.erase(result.size() - 1);
0185 else
0186 {
0187 if (expon > 0)
0188 --expon;
0189 else
0190 ++expon;
0191 ++digits;
0192 }
0193 }
0194 BOOST_MP_ASSERT(org_digits >= 0);
0195 if (isneg)
0196 result.insert(static_cast<std::string::size_type>(0), 1, '-');
0197 format_float_string(result, expon, org_digits, f, iszero);
0198
0199 return result;
0200 }
0201
0202 template <class Backend>
0203 void convert_from_string(Backend& b, const char* p)
0204 {
0205 using default_ops::eval_add;
0206 using default_ops::eval_divide;
0207 using default_ops::eval_multiply;
0208 using default_ops::eval_pow;
0209
0210 using ui_type = typename std::tuple_element<0, typename Backend::unsigned_types>::type;
0211 b = ui_type(0);
0212 if (!p || (*p == 0))
0213 return;
0214
0215 bool is_neg = false;
0216 bool is_neg_expon = false;
0217 constexpr ui_type ten = ui_type(10);
0218 typename Backend::exponent_type expon = 0;
0219 int digits_seen = 0;
0220
0221 using limits = std::numeric_limits<number<Backend, et_off>>;
0222
0223 constexpr int max_digits = limits::is_specialized ? limits::max_digits10 + 1 : INT_MAX;
0224
0225 if (*p == '+')
0226 ++p;
0227 else if (*p == '-')
0228 {
0229 is_neg = true;
0230 ++p;
0231 }
0232 if ((std::strcmp(p, "nan") == 0) || (std::strcmp(p, "NaN") == 0) || (std::strcmp(p, "NAN") == 0))
0233 {
0234 eval_divide(b, ui_type(0));
0235 if (is_neg)
0236 b.negate();
0237 return;
0238 }
0239 if ((std::strcmp(p, "inf") == 0) || (std::strcmp(p, "Inf") == 0) || (std::strcmp(p, "INF") == 0))
0240 {
0241 b = ui_type(1);
0242 eval_divide(b, ui_type(0));
0243 if (is_neg)
0244 b.negate();
0245 return;
0246 }
0247
0248
0249
0250 while (std::isdigit(*p))
0251 {
0252 eval_multiply(b, ten);
0253 eval_add(b, ui_type(*p - '0'));
0254 ++p;
0255 ++digits_seen;
0256 }
0257 if (*p == '.')
0258 {
0259
0260
0261
0262
0263 ++p;
0264 while (std::isdigit(*p))
0265 {
0266 eval_multiply(b, ten);
0267 eval_add(b, ui_type(*p - '0'));
0268 ++p;
0269 --expon;
0270 if (++digits_seen > max_digits)
0271 break;
0272 }
0273 while (std::isdigit(*p))
0274 ++p;
0275 }
0276
0277
0278
0279 if ((*p == 'e') || (*p == 'E'))
0280 {
0281 ++p;
0282 if (*p == '+')
0283 ++p;
0284 else if (*p == '-')
0285 {
0286 is_neg_expon = true;
0287 ++p;
0288 }
0289 typename Backend::exponent_type e2 = 0;
0290 while (std::isdigit(*p))
0291 {
0292 e2 *= 10;
0293 e2 += (*p - '0');
0294 ++p;
0295 }
0296 if (is_neg_expon)
0297 e2 = -e2;
0298 expon += e2;
0299 }
0300 if (expon)
0301 {
0302
0303
0304
0305
0306 Backend t;
0307 t = ten;
0308 if (expon > limits::min_exponent10 + 2)
0309 {
0310 eval_pow(t, t, expon);
0311 eval_multiply(b, t);
0312 }
0313 else
0314 {
0315 eval_pow(t, t, expon + digits_seen + 1);
0316 eval_multiply(b, t);
0317 t = ten;
0318 eval_pow(t, t, -digits_seen - 1);
0319 eval_multiply(b, t);
0320 }
0321 }
0322 if (is_neg)
0323 b.negate();
0324 if (*p)
0325 {
0326
0327 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Unexpected characters in string being interpreted as a float128."));
0328 }
0329 }
0330
0331 }}}
0332
0333 #endif