dtoa.h
Go to the documentation of this file.
1 // Tencent is pleased to support the open source community by making RapidJSON available.
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 // This is a C++ header-only implementation of Grisu2 algorithm from the publication:
16 // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
17 // integers." ACM Sigplan Notices 45.6 (2010): 233-243.
18 
19 #ifndef RAPIDJSON_DTOA_
20 #define RAPIDJSON_DTOA_
21 
22 #include "itoa.h" // GetDigitsLut()
23 #include "diyfp.h"
24 #include "ieee754.h"
25 
27 namespace internal
28 {
29 #if __GNUC__
30 RAPIDJSON_DIAG_PUSH
31 RAPIDJSON_DIAG_OFF(effc++)
32 RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings
33  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
34 #endif
35 
36 inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w)
37 {
38  while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w ||
39  wp_w - rest > rest + ten_kappa - wp_w))
40  {
41  buffer[len - 1]--;
42  rest += ten_kappa;
43  }
44 }
45 
47 {
48  // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
49  if (n < 10)
50  return 1;
51  if (n < 100)
52  return 2;
53  if (n < 1000)
54  return 3;
55  if (n < 10000)
56  return 4;
57  if (n < 100000)
58  return 5;
59  if (n < 1000000)
60  return 6;
61  if (n < 10000000)
62  return 7;
63  if (n < 100000000)
64  return 8;
65  // Will not reach 10 digits in DigitGen()
66  // if (n < 1000000000) return 9;
67  // return 10;
68  return 9;
69 }
70 
71 inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K)
72 {
73  static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
74  const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
75  const DiyFp wp_w = Mp - W;
76  uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
77  uint64_t p2 = Mp.f & (one.f - 1);
78  int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
79  *len = 0;
80 
81  while (kappa > 0)
82  {
83  uint32_t d = 0;
84  switch (kappa)
85  {
86  case 9:
87  d = p1 / 100000000;
88  p1 %= 100000000;
89  break;
90  case 8:
91  d = p1 / 10000000;
92  p1 %= 10000000;
93  break;
94  case 7:
95  d = p1 / 1000000;
96  p1 %= 1000000;
97  break;
98  case 6:
99  d = p1 / 100000;
100  p1 %= 100000;
101  break;
102  case 5:
103  d = p1 / 10000;
104  p1 %= 10000;
105  break;
106  case 4:
107  d = p1 / 1000;
108  p1 %= 1000;
109  break;
110  case 3:
111  d = p1 / 100;
112  p1 %= 100;
113  break;
114  case 2:
115  d = p1 / 10;
116  p1 %= 10;
117  break;
118  case 1:
119  d = p1;
120  p1 = 0;
121  break;
122  default:;
123  }
124  if (d || *len)
125  buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
126  kappa--;
127  uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
128  if (tmp <= delta)
129  {
130  *K += kappa;
131  GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
132  return;
133  }
134  }
135 
136  // kappa = 0
137  for (;;)
138  {
139  p2 *= 10;
140  delta *= 10;
141  char d = static_cast<char>(p2 >> -one.e);
142  if (d || *len)
143  buffer[(*len)++] = static_cast<char>('0' + d);
144  p2 &= one.f - 1;
145  kappa--;
146  if (p2 < delta)
147  {
148  *K += kappa;
149  int index = -kappa;
150  GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
151  return;
152  }
153  }
154 }
155 
156 inline void Grisu2(double value, char* buffer, int* length, int* K)
157 {
158  const DiyFp v(value);
159  DiyFp w_m, w_p;
160  v.NormalizedBoundaries(&w_m, &w_p);
161 
162  const DiyFp c_mk = GetCachedPower(w_p.e, K);
163  const DiyFp W = v.Normalize() * c_mk;
164  DiyFp Wp = w_p * c_mk;
165  DiyFp Wm = w_m * c_mk;
166  Wm.f++;
167  Wp.f--;
168  DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
169 }
170 
171 inline char* WriteExponent(int K, char* buffer)
172 {
173  if (K < 0)
174  {
175  *buffer++ = '-';
176  K = -K;
177  }
178 
179  if (K >= 100)
180  {
181  *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
182  K %= 100;
183  const char* d = GetDigitsLut() + K * 2;
184  *buffer++ = d[0];
185  *buffer++ = d[1];
186  }
187  else if (K >= 10)
188  {
189  const char* d = GetDigitsLut() + K * 2;
190  *buffer++ = d[0];
191  *buffer++ = d[1];
192  }
193  else
194  *buffer++ = static_cast<char>('0' + static_cast<char>(K));
195 
196  return buffer;
197 }
198 
199 inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces)
200 {
201  const int kk = length + k; // 10^(kk-1) <= v < 10^kk
202 
203  if (0 <= k && kk <= 21)
204  {
205  // 1234e7 -> 12340000000
206  for (int i = length; i < kk; i++)
207  buffer[i] = '0';
208  buffer[kk] = '.';
209  buffer[kk + 1] = '0';
210  return &buffer[kk + 2];
211  }
212  else if (0 < kk && kk <= 21)
213  {
214  // 1234e-2 -> 12.34
215  std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
216  buffer[kk] = '.';
217  if (0 > k + maxDecimalPlaces)
218  {
219  // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
220  // Remove extra trailing zeros (at least one) after truncation.
221  for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
222  if (buffer[i] != '0')
223  return &buffer[i + 1];
224  return &buffer[kk + 2]; // Reserve one zero
225  }
226  else
227  return &buffer[length + 1];
228  }
229  else if (-6 < kk && kk <= 0)
230  {
231  // 1234e-6 -> 0.001234
232  const int offset = 2 - kk;
233  std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
234  buffer[0] = '0';
235  buffer[1] = '.';
236  for (int i = 2; i < offset; i++)
237  buffer[i] = '0';
238  if (length - kk > maxDecimalPlaces)
239  {
240  // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
241  // Remove extra trailing zeros (at least one) after truncation.
242  for (int i = maxDecimalPlaces + 1; i > 2; i--)
243  if (buffer[i] != '0')
244  return &buffer[i + 1];
245  return &buffer[3]; // Reserve one zero
246  }
247  else
248  return &buffer[length + offset];
249  }
250  else if (kk < -maxDecimalPlaces)
251  {
252  // Truncate to zero
253  buffer[0] = '0';
254  buffer[1] = '.';
255  buffer[2] = '0';
256  return &buffer[3];
257  }
258  else if (length == 1)
259  {
260  // 1e30
261  buffer[1] = 'e';
262  return WriteExponent(kk - 1, &buffer[2]);
263  }
264  else
265  {
266  // 1234e30 -> 1.234e33
267  std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
268  buffer[1] = '.';
269  buffer[length + 1] = 'e';
270  return WriteExponent(kk - 1, &buffer[0 + length + 2]);
271  }
272 }
273 
274 inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324)
275 {
276  RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
277  Double d(value);
278  if (d.IsZero())
279  {
280  if (d.Sign())
281  *buffer++ = '-'; // -0.0, Issue #289
282  buffer[0] = '0';
283  buffer[1] = '.';
284  buffer[2] = '0';
285  return &buffer[3];
286  }
287  else
288  {
289  if (value < 0)
290  {
291  *buffer++ = '-';
292  value = -value;
293  }
294  int length, K;
295  Grisu2(value, buffer, &length, &K);
296  return Prettify(buffer, length, K, maxDecimalPlaces);
297  }
298 }
299 
300 #if __GNUC__
301 RAPIDJSON_DIAG_POP
302 #endif
303 
304 } // namespace internal
306 
307 #endif // RAPIDJSON_DTOA_
d
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:416
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:126
char * Prettify(char *buffer, int length, int k, int maxDecimalPlaces)
Definition: dtoa.h:199
const char * GetDigitsLut()
Definition: itoa.h:23
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
DiyFp Normalize() const
Definition: diyfp.h:113
bool Sign() const
Definition: ieee754.h:51
void Grisu2(double value, char *buffer, int *length, int *K)
Definition: dtoa.h:156
unsigned int uint32_t
Definition: stdint.h:126
bool IsZero() const
Definition: ieee754.h:80
void GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w)
Definition: dtoa.h:36
unsigned __int64 uint64_t
Definition: stdint.h:136
uint64_t f
Definition: diyfp.h:191
void DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K)
Definition: dtoa.h:71
char * WriteExponent(int K, char *buffer)
Definition: dtoa.h:171
int CountDecimalDigit32(uint32_t n)
Definition: dtoa.h:46
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1563
void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const
Definition: diyfp.h:147
DiyFp GetCachedPower(int e, int *K)
Definition: diyfp.h:255
char * dtoa(double value, char *buffer, int maxDecimalPlaces=324)
Definition: dtoa.h:274


xbot_talker
Author(s): wangxiaoyun
autogenerated on Sat Oct 10 2020 03:27:53