strtod.h
Go to the documentation of this file.
1 // Tencent is pleased to support the open source community by making RapidJSON
2 // available.
3 //
4 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
5 // rights reserved.
6 //
7 // Licensed under the MIT License (the "License"); you may not use this file
8 // except in compliance with the License. You may obtain a copy of the License
9 // at
10 //
11 // http://opensource.org/licenses/MIT
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 // License for the specific language governing permissions and limitations under
17 // the License.
18 
19 #ifndef RAPIDJSON_STRTOD_
20 #define RAPIDJSON_STRTOD_
21 
22 #include <climits>
23 #include <limits>
24 #include "biginteger.h"
25 #include "diyfp.h"
26 #include "ieee754.h"
27 #include "pow10.h"
28 
30 namespace internal {
31 
32 inline double FastPath(double significand, int exp) {
33  if (exp < -308)
34  return 0.0;
35  else if (exp >= 0)
36  return significand * internal::Pow10(exp);
37  else
38  return significand / internal::Pow10(-exp);
39 }
40 
41 inline double StrtodNormalPrecision(double d, int p) {
42  if (p < -308) {
43  // Prevent expSum < -308, making Pow10(p) = 0
44  d = FastPath(d, -308);
45  d = FastPath(d, p + 308);
46  } else
47  d = FastPath(d, p);
48  return d;
49 }
50 
51 template <typename T>
52 inline T Min3(T a, T b, T c) {
53  T m = a;
54  if (m > b) m = b;
55  if (m > c) m = c;
56  return m;
57 }
58 
59 inline int CheckWithinHalfULP(double b, const BigInteger &d, int dExp) {
60  const Double db(b);
61  const uint64_t bInt = db.IntegerSignificand();
62  const int bExp = db.IntegerExponent();
63  const int hExp = bExp - 1;
64 
65  int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0,
66  hS_Exp5 = 0;
67 
68  // Adjust for decimal exponent
69  if (dExp >= 0) {
70  dS_Exp2 += dExp;
71  dS_Exp5 += dExp;
72  } else {
73  bS_Exp2 -= dExp;
74  bS_Exp5 -= dExp;
75  hS_Exp2 -= dExp;
76  hS_Exp5 -= dExp;
77  }
78 
79  // Adjust for binary exponent
80  if (bExp >= 0)
81  bS_Exp2 += bExp;
82  else {
83  dS_Exp2 -= bExp;
84  hS_Exp2 -= bExp;
85  }
86 
87  // Adjust for half ulp exponent
88  if (hExp >= 0)
89  hS_Exp2 += hExp;
90  else {
91  dS_Exp2 -= hExp;
92  bS_Exp2 -= hExp;
93  }
94 
95  // Remove common power of two factor from all three scaled values
96  int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
97  dS_Exp2 -= common_Exp2;
98  bS_Exp2 -= common_Exp2;
99  hS_Exp2 -= common_Exp2;
100 
101  BigInteger dS = d;
102  dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<=
103  static_cast<unsigned>(dS_Exp2);
104 
105  BigInteger bS(bInt);
106  bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<=
107  static_cast<unsigned>(bS_Exp2);
108 
109  BigInteger hS(1);
110  hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<=
111  static_cast<unsigned>(hS_Exp2);
112 
113  BigInteger delta(0);
114  dS.Difference(bS, &delta);
115 
116  return delta.Compare(hS);
117 }
118 
119 inline bool StrtodFast(double d, int p, double *result) {
120  // Use fast path for string-to-double conversion if possible
121  // see
122  // http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
123  if (p > 22 && p < 22 + 16) {
124  // Fast Path Cases In Disguise
125  d *= internal::Pow10(p - 22);
126  p = 22;
127  }
128 
129  if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
130  *result = FastPath(d, p);
131  return true;
132  } else
133  return false;
134 }
135 
136 // Compute an approximation and see if it is within 1/2 ULP
137 inline bool StrtodDiyFp(const char *decimals, int dLen, int dExp,
138  double *result) {
139  uint64_t significand = 0;
140  int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 =
141  // 0x1999999999999999
142  for (; i < dLen; i++) {
143  if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
144  (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) &&
145  decimals[i] > '5'))
146  break;
147  significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
148  }
149 
150  if (i < dLen && decimals[i] >= '5') // Rounding
151  significand++;
152 
153  int remaining = dLen - i;
154  const int kUlpShift = 3;
155  const int kUlp = 1 << kUlpShift;
156  int64_t error = (remaining == 0) ? 0 : kUlp / 2;
157 
158  DiyFp v(significand, 0);
159  v = v.Normalize();
160  error <<= -v.e;
161 
162  dExp += remaining;
163 
164  int actualExp;
165  DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
166  if (actualExp != dExp) {
167  static const DiyFp kPow10[] = {
168  DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
169  DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
170  DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
171  DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
172  DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
173  DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
174  DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
175  };
176  int adjustment = dExp - actualExp;
177  RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
178  v = v * kPow10[adjustment - 1];
179  if (dLen + adjustment >
180  19) // has more digits than decimal digits in 64-bit
181  error += kUlp / 2;
182  }
183 
184  v = v * cachedPower;
185 
186  error += kUlp + (error == 0 ? 0 : 1);
187 
188  const int oldExp = v.e;
189  v = v.Normalize();
190  error <<= oldExp - v.e;
191 
192  const int effectiveSignificandSize =
194  int precisionSize = 64 - effectiveSignificandSize;
195  if (precisionSize + kUlpShift >= 64) {
196  int scaleExp = (precisionSize + kUlpShift) - 63;
197  v.f >>= scaleExp;
198  v.e += scaleExp;
199  error = (error >> scaleExp) + 1 + kUlp;
200  precisionSize -= scaleExp;
201  }
202 
203  DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
204  const uint64_t precisionBits =
205  (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
206  const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
207  if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
208  rounded.f++;
209  if (rounded.f & (DiyFp::kDpHiddenBit
210  << 1)) { // rounding overflows mantissa (issue #340)
211  rounded.f >>= 1;
212  rounded.e++;
213  }
214  }
215 
216  *result = rounded.ToDouble();
217 
218  return halfWay - static_cast<unsigned>(error) >= precisionBits ||
219  precisionBits >= halfWay + static_cast<unsigned>(error);
220 }
221 
222 inline double StrtodBigInteger(double approx, const char *decimals, int dLen,
223  int dExp) {
224  RAPIDJSON_ASSERT(dLen >= 0);
225  const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
226  Double a(approx);
227  int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
228  if (cmp < 0)
229  return a.Value(); // within half ULP
230  else if (cmp == 0) {
231  // Round towards even
232  if (a.Significand() & 1)
233  return a.NextPositiveDouble();
234  else
235  return a.Value();
236  } else // adjustment
237  return a.NextPositiveDouble();
238 }
239 
240 inline double StrtodFullPrecision(double d, int p, const char *decimals,
241  size_t length, size_t decimalPosition,
242  int exp) {
243  RAPIDJSON_ASSERT(d >= 0.0);
244  RAPIDJSON_ASSERT(length >= 1);
245 
246  double result = 0.0;
247  if (StrtodFast(d, p, &result)) return result;
248 
249  RAPIDJSON_ASSERT(length <= INT_MAX);
250  int dLen = static_cast<int>(length);
251 
252  RAPIDJSON_ASSERT(length >= decimalPosition);
253  RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
254  int dExpAdjust = static_cast<int>(length - decimalPosition);
255 
256  RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
257  int dExp = exp - dExpAdjust;
258 
259  // Make sure length+dExp does not overflow
260  RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
261 
262  // Trim leading zeros
263  while (dLen > 0 && *decimals == '0') {
264  dLen--;
265  decimals++;
266  }
267 
268  // Trim trailing zeros
269  while (dLen > 0 && decimals[dLen - 1] == '0') {
270  dLen--;
271  dExp++;
272  }
273 
274  if (dLen == 0) { // Buffer only contains zeros.
275  return 0.0;
276  }
277 
278  // Trim right-most digits
279  const int kMaxDecimalDigit = 767 + 1;
280  if (dLen > kMaxDecimalDigit) {
281  dExp += dLen - kMaxDecimalDigit;
282  dLen = kMaxDecimalDigit;
283  }
284 
285  // If too small, underflow to zero.
286  // Any x <= 10^-324 is interpreted as zero.
287  if (dLen + dExp <= -324) return 0.0;
288 
289  // If too large, overflow to infinity.
290  // Any x >= 10^309 is interpreted as +infinity.
291  if (dLen + dExp > 309) return std::numeric_limits<double>::infinity();
292 
293  if (StrtodDiyFp(decimals, dLen, dExp, &result)) return result;
294 
295  // Use approximation from StrtodDiyFp and make adjustment with BigInteger
296  // comparison
297  return StrtodBigInteger(result, decimals, dLen, dExp);
298 }
299 
300 } // namespace internal
302 
303 #endif // RAPIDJSON_STRTOD_
double StrtodFullPrecision(double d, int p, const char *decimals, size_t length, size_t decimalPosition, int exp)
Definition: strtod.h:240
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:433
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition: rapidjson.h:306
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:131
uint64_t Significand() const
Definition: ieee754.h:42
DiyFp GetCachedPower10(int exp, int *outExp)
Definition: diyfp.h:286
int Compare(const BigInteger &rhs) const
Definition: biginteger.h:211
static int EffectiveSignificandSize(int order)
Definition: ieee754.h:70
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:128
DiyFp Normalize() const
Definition: diyfp.h:105
double Value() const
Definition: ieee754.h:33
double NextPositiveDouble() const
Definition: ieee754.h:36
bool StrtodFast(double d, int p, double *result)
Definition: strtod.h:119
double StrtodNormalPrecision(double d, int p)
Definition: strtod.h:41
int CheckWithinHalfULP(double b, const BigInteger &d, int dExp)
Definition: strtod.h:59
double ToDouble() const
Definition: diyfp.h:131
bool StrtodDiyFp(const char *decimals, int dLen, int dExp, double *result)
Definition: strtod.h:137
unsigned __int64 uint64_t
Definition: stdint.h:137
uint64_t f
Definition: diyfp.h:165
uint64_t IntegerSignificand() const
Definition: ieee754.h:60
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1365
double Pow10(int n)
Computes integer powers of 10 in double (10.0^n).
Definition: pow10.h:32
int IntegerExponent() const
Definition: ieee754.h:63
signed __int64 int64_t
Definition: stdint.h:136
double StrtodBigInteger(double approx, const char *decimals, int dLen, int dExp)
Definition: strtod.h:222
T Min3(T a, T b, T c)
Definition: strtod.h:52
BigInteger & MultiplyPow5(unsigned exp)
Definition: biginteger.h:159
static const uint64_t kDpHiddenBit
Definition: diyfp.h:162
double FastPath(double significand, int exp)
Definition: strtod.h:32
bool Difference(const BigInteger &rhs, BigInteger *out) const
Definition: biginteger.h:184


livox_ros_driver
Author(s): Livox Dev Team
autogenerated on Mon Mar 15 2021 02:40:46