File indexing completed on 2024-11-15 09:55:00
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef RAPIDJSON_STRTOD_
0016 #define RAPIDJSON_STRTOD_
0017
0018 #include "ieee754.h"
0019 #include "biginteger.h"
0020 #include "diyfp.h"
0021 #include "pow10.h"
0022 #include <climits>
0023 #include <limits>
0024
0025 RAPIDJSON_NAMESPACE_BEGIN
0026 namespace internal {
0027
0028 inline double FastPath(double significand, int exp) {
0029 if (exp < -308)
0030 return 0.0;
0031 else if (exp >= 0)
0032 return significand * internal::Pow10(exp);
0033 else
0034 return significand / internal::Pow10(-exp);
0035 }
0036
0037 inline double StrtodNormalPrecision(double d, int p) {
0038 if (p < -308) {
0039
0040 d = FastPath(d, -308);
0041 d = FastPath(d, p + 308);
0042 }
0043 else
0044 d = FastPath(d, p);
0045 return d;
0046 }
0047
0048 template <typename T>
0049 inline T Min3(T a, T b, T c) {
0050 T m = a;
0051 if (m > b) m = b;
0052 if (m > c) m = c;
0053 return m;
0054 }
0055
0056 inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
0057 const Double db(b);
0058 const uint64_t bInt = db.IntegerSignificand();
0059 const int bExp = db.IntegerExponent();
0060 const int hExp = bExp - 1;
0061
0062 int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
0063
0064
0065 if (dExp >= 0) {
0066 dS_Exp2 += dExp;
0067 dS_Exp5 += dExp;
0068 }
0069 else {
0070 bS_Exp2 -= dExp;
0071 bS_Exp5 -= dExp;
0072 hS_Exp2 -= dExp;
0073 hS_Exp5 -= dExp;
0074 }
0075
0076
0077 if (bExp >= 0)
0078 bS_Exp2 += bExp;
0079 else {
0080 dS_Exp2 -= bExp;
0081 hS_Exp2 -= bExp;
0082 }
0083
0084
0085 if (hExp >= 0)
0086 hS_Exp2 += hExp;
0087 else {
0088 dS_Exp2 -= hExp;
0089 bS_Exp2 -= hExp;
0090 }
0091
0092
0093 int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
0094 dS_Exp2 -= common_Exp2;
0095 bS_Exp2 -= common_Exp2;
0096 hS_Exp2 -= common_Exp2;
0097
0098 BigInteger dS = d;
0099 dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
0100
0101 BigInteger bS(bInt);
0102 bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
0103
0104 BigInteger hS(1);
0105 hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
0106
0107 BigInteger delta(0);
0108 dS.Difference(bS, &delta);
0109
0110 return delta.Compare(hS);
0111 }
0112
0113 inline bool StrtodFast(double d, int p, double* result) {
0114
0115
0116 if (p > 22 && p < 22 + 16) {
0117
0118 d *= internal::Pow10(p - 22);
0119 p = 22;
0120 }
0121
0122 if (p >= -22 && p <= 22 && d <= 9007199254740991.0) {
0123 *result = FastPath(d, p);
0124 return true;
0125 }
0126 else
0127 return false;
0128 }
0129
0130
0131 template<typename Ch>
0132 inline bool StrtodDiyFp(const Ch* decimals, int dLen, int dExp, double* result) {
0133 uint64_t significand = 0;
0134 int i = 0;
0135 for (; i < dLen; i++) {
0136 if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
0137 (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > Ch('5')))
0138 break;
0139 significand = significand * 10u + static_cast<unsigned>(decimals[i] - Ch('0'));
0140 }
0141
0142 if (i < dLen && decimals[i] >= Ch('5'))
0143 significand++;
0144
0145 int remaining = dLen - i;
0146 const int kUlpShift = 3;
0147 const int kUlp = 1 << kUlpShift;
0148 int64_t error = (remaining == 0) ? 0 : kUlp / 2;
0149
0150 DiyFp v(significand, 0);
0151 v = v.Normalize();
0152 error <<= -v.e;
0153
0154 dExp += remaining;
0155
0156 int actualExp;
0157 DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
0158 if (actualExp != dExp) {
0159 static const DiyFp kPow10[] = {
0160 DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60),
0161 DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57),
0162 DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54),
0163 DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50),
0164 DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47),
0165 DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44),
0166 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40)
0167 };
0168 int adjustment = dExp - actualExp;
0169 RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
0170 v = v * kPow10[adjustment - 1];
0171 if (dLen + adjustment > 19)
0172 error += kUlp / 2;
0173 }
0174
0175 v = v * cachedPower;
0176
0177 error += kUlp + (error == 0 ? 0 : 1);
0178
0179 const int oldExp = v.e;
0180 v = v.Normalize();
0181 error <<= oldExp - v.e;
0182
0183 const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
0184 int precisionSize = 64 - effectiveSignificandSize;
0185 if (precisionSize + kUlpShift >= 64) {
0186 int scaleExp = (precisionSize + kUlpShift) - 63;
0187 v.f >>= scaleExp;
0188 v.e += scaleExp;
0189 error = (error >> scaleExp) + 1 + kUlp;
0190 precisionSize -= scaleExp;
0191 }
0192
0193 DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
0194 const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
0195 const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
0196 if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
0197 rounded.f++;
0198 if (rounded.f & (DiyFp::kDpHiddenBit << 1)) {
0199 rounded.f >>= 1;
0200 rounded.e++;
0201 }
0202 }
0203
0204 *result = rounded.ToDouble();
0205
0206 return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
0207 }
0208
0209 template<typename Ch>
0210 inline double StrtodBigInteger(double approx, const Ch* decimals, int dLen, int dExp) {
0211 RAPIDJSON_ASSERT(dLen >= 0);
0212 const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
0213 Double a(approx);
0214 int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
0215 if (cmp < 0)
0216 return a.Value();
0217 else if (cmp == 0) {
0218
0219 if (a.Significand() & 1)
0220 return a.NextPositiveDouble();
0221 else
0222 return a.Value();
0223 }
0224 else
0225 return a.NextPositiveDouble();
0226 }
0227
0228 template<typename Ch>
0229 inline double StrtodFullPrecision(double d, int p, const Ch* decimals, size_t length, size_t decimalPosition, int exp) {
0230 RAPIDJSON_ASSERT(d >= 0.0);
0231 RAPIDJSON_ASSERT(length >= 1);
0232
0233 double result = 0.0;
0234 if (StrtodFast(d, p, &result))
0235 return result;
0236
0237 RAPIDJSON_ASSERT(length <= INT_MAX);
0238 int dLen = static_cast<int>(length);
0239
0240 RAPIDJSON_ASSERT(length >= decimalPosition);
0241 RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
0242 int dExpAdjust = static_cast<int>(length - decimalPosition);
0243
0244 RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
0245 int dExp = exp - dExpAdjust;
0246
0247
0248 RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
0249
0250
0251 while (dLen > 0 && *decimals == '0') {
0252 dLen--;
0253 decimals++;
0254 }
0255
0256
0257 while (dLen > 0 && decimals[dLen - 1] == '0') {
0258 dLen--;
0259 dExp++;
0260 }
0261
0262 if (dLen == 0) {
0263 return 0.0;
0264 }
0265
0266
0267 const int kMaxDecimalDigit = 767 + 1;
0268 if (dLen > kMaxDecimalDigit) {
0269 dExp += dLen - kMaxDecimalDigit;
0270 dLen = kMaxDecimalDigit;
0271 }
0272
0273
0274
0275 if (dLen + dExp <= -324)
0276 return 0.0;
0277
0278
0279
0280 if (dLen + dExp > 309)
0281 return std::numeric_limits<double>::infinity();
0282
0283 if (StrtodDiyFp(decimals, dLen, dExp, &result))
0284 return result;
0285
0286
0287 return StrtodBigInteger(result, decimals, dLen, dExp);
0288 }
0289
0290 }
0291 RAPIDJSON_NAMESPACE_END
0292
0293 #endif