/home/docs/checkouts/readthedocs.org/user_builds/advanced-micro-devices-composable-kernel/checkouts/develop/include/rapidjson/internal/dtoa.h Source File

/home/docs/checkouts/readthedocs.org/user_builds/advanced-micro-devices-composable-kernel/checkouts/develop/include/rapidjson/internal/dtoa.h Source File#

Composable Kernel: /home/docs/checkouts/readthedocs.org/user_builds/advanced-micro-devices-composable-kernel/checkouts/develop/include/rapidjson/internal/dtoa.h Source File
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.
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 #ifdef __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
37 GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w)
38 {
39  while(rest < wp_w && delta - rest >= ten_kappa &&
40  (rest + ten_kappa < wp_w ||
41  wp_w - rest > rest + ten_kappa - wp_w))
42  {
43  buffer[len - 1]--;
44  rest += ten_kappa;
45  }
46 }
47 
49 {
50  // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
51  if(n < 10)
52  return 1;
53  if(n < 100)
54  return 2;
55  if(n < 1000)
56  return 3;
57  if(n < 10000)
58  return 4;
59  if(n < 100000)
60  return 5;
61  if(n < 1000000)
62  return 6;
63  if(n < 10000000)
64  return 7;
65  if(n < 100000000)
66  return 8;
67  // Will not reach 10 digits in DigitGen()
68  // if (n < 1000000000) return 9;
69  // return 10;
70  return 9;
71 }
72 
73 inline void
74 DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K)
75 {
76  static const uint64_t kPow10[] = {1ULL,
77  10ULL,
78  100ULL,
79  1000ULL,
80  10000ULL,
81  100000ULL,
82  1000000ULL,
83  10000000ULL,
84  100000000ULL,
85  1000000000ULL,
86  10000000000ULL,
87  100000000000ULL,
88  1000000000000ULL,
89  10000000000000ULL,
90  100000000000000ULL,
91  1000000000000000ULL,
92  10000000000000000ULL,
93  100000000000000000ULL,
94  1000000000000000000ULL,
95  10000000000000000000ULL};
96  const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
97  const DiyFp wp_w = Mp - W;
98  uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
99  uint64_t p2 = Mp.f & (one.f - 1);
100  int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
101  *len = 0;
102 
103  while(kappa > 0)
104  {
105  uint32_t d = 0;
106  switch(kappa)
107  {
108  case 9:
109  d = p1 / 100000000;
110  p1 %= 100000000;
111  break;
112  case 8:
113  d = p1 / 10000000;
114  p1 %= 10000000;
115  break;
116  case 7:
117  d = p1 / 1000000;
118  p1 %= 1000000;
119  break;
120  case 6:
121  d = p1 / 100000;
122  p1 %= 100000;
123  break;
124  case 5:
125  d = p1 / 10000;
126  p1 %= 10000;
127  break;
128  case 4:
129  d = p1 / 1000;
130  p1 %= 1000;
131  break;
132  case 3:
133  d = p1 / 100;
134  p1 %= 100;
135  break;
136  case 2:
137  d = p1 / 10;
138  p1 %= 10;
139  break;
140  case 1:
141  d = p1;
142  p1 = 0;
143  break;
144  default:;
145  }
146  if(d || *len)
147  buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
148  kappa--;
149  uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
150  if(tmp <= delta)
151  {
152  *K += kappa;
153  GrisuRound(buffer, *len, delta, tmp, kPow10[kappa] << -one.e, wp_w.f);
154  return;
155  }
156  }
157 
158  // kappa = 0
159  for(;;)
160  {
161  p2 *= 10;
162  delta *= 10;
163  char d = static_cast<char>(p2 >> -one.e);
164  if(d || *len)
165  buffer[(*len)++] = static_cast<char>('0' + d);
166  p2 &= one.f - 1;
167  kappa--;
168  if(p2 < delta)
169  {
170  *K += kappa;
171  int index = -kappa;
172  GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 20 ? kPow10[index] : 0));
173  return;
174  }
175  }
176 }
177 
178 inline void Grisu2(double value, char* buffer, int* length, int* K)
179 {
180  const DiyFp v(value);
181  DiyFp w_m, w_p;
182  v.NormalizedBoundaries(&w_m, &w_p);
183 
184  const DiyFp c_mk = GetCachedPower(w_p.e, K);
185  const DiyFp W = v.Normalize() * c_mk;
186  DiyFp Wp = w_p * c_mk;
187  DiyFp Wm = w_m * c_mk;
188  Wm.f++;
189  Wp.f--;
190  DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
191 }
192 
193 inline char* WriteExponent(int K, char* buffer)
194 {
195  if(K < 0)
196  {
197  *buffer++ = '-';
198  K = -K;
199  }
200 
201  if(K >= 100)
202  {
203  *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
204  K %= 100;
205  const char* d = GetDigitsLut() + K * 2;
206  *buffer++ = d[0];
207  *buffer++ = d[1];
208  }
209  else if(K >= 10)
210  {
211  const char* d = GetDigitsLut() + K * 2;
212  *buffer++ = d[0];
213  *buffer++ = d[1];
214  }
215  else
216  *buffer++ = static_cast<char>('0' + static_cast<char>(K));
217 
218  return buffer;
219 }
220 
221 inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces)
222 {
223  const int kk = length + k; // 10^(kk-1) <= v < 10^kk
224 
225  if(0 <= k && kk <= 21)
226  {
227  // 1234e7 -> 12340000000
228  for(int i = length; i < kk; i++)
229  buffer[i] = '0';
230  buffer[kk] = '.';
231  buffer[kk + 1] = '0';
232  return &buffer[kk + 2];
233  }
234  else if(0 < kk && kk <= 21)
235  {
236  // 1234e-2 -> 12.34
237  std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
238  buffer[kk] = '.';
239  if(0 > k + maxDecimalPlaces)
240  {
241  // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
242  // Remove extra trailing zeros (at least one) after truncation.
243  for(int i = kk + maxDecimalPlaces; i > kk + 1; i--)
244  if(buffer[i] != '0')
245  return &buffer[i + 1];
246  return &buffer[kk + 2]; // Reserve one zero
247  }
248  else
249  return &buffer[length + 1];
250  }
251  else if(-6 < kk && kk <= 0)
252  {
253  // 1234e-6 -> 0.001234
254  const int offset = 2 - kk;
255  std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
256  buffer[0] = '0';
257  buffer[1] = '.';
258  for(int i = 2; i < offset; i++)
259  buffer[i] = '0';
260  if(length - kk > maxDecimalPlaces)
261  {
262  // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
263  // Remove extra trailing zeros (at least one) after truncation.
264  for(int i = maxDecimalPlaces + 1; i > 2; i--)
265  if(buffer[i] != '0')
266  return &buffer[i + 1];
267  return &buffer[3]; // Reserve one zero
268  }
269  else
270  return &buffer[length + offset];
271  }
272  else if(kk < -maxDecimalPlaces)
273  {
274  // Truncate to zero
275  buffer[0] = '0';
276  buffer[1] = '.';
277  buffer[2] = '0';
278  return &buffer[3];
279  }
280  else if(length == 1)
281  {
282  // 1e30
283  buffer[1] = 'e';
284  return WriteExponent(kk - 1, &buffer[2]);
285  }
286  else
287  {
288  // 1234e30 -> 1.234e33
289  std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
290  buffer[1] = '.';
291  buffer[length + 1] = 'e';
292  return WriteExponent(kk - 1, &buffer[0 + length + 2]);
293  }
294 }
295 
296 inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324)
297 {
298  RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
299  Double d(value);
300  if(d.IsZero())
301  {
302  if(d.Sign())
303  *buffer++ = '-'; // -0.0, Issue #289
304  buffer[0] = '0';
305  buffer[1] = '.';
306  buffer[2] = '0';
307  return &buffer[3];
308  }
309  else
310  {
311  if(value < 0)
312  {
313  *buffer++ = '-';
314  value = -value;
315  }
316  int length, K;
317  Grisu2(value, buffer, &length, &K);
318  return Prettify(buffer, length, K, maxDecimalPlaces);
319  }
320 }
321 
322 #ifdef __GNUC__
323 RAPIDJSON_DIAG_POP
324 #endif
325 
326 } // namespace internal
328 
329 #endif // RAPIDJSON_DTOA_
Definition: ieee754.h:24
bool IsZero() const
Definition: ieee754.h:50
bool Sign() const
Definition: ieee754.h:39
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:451
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:124
Definition: allocators.h:459
char * Prettify(char *buffer, int length, int k, int maxDecimalPlaces)
Definition: dtoa.h:221
void GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w)
Definition: dtoa.h:37
char * dtoa(double value, char *buffer, int maxDecimalPlaces=324)
Definition: dtoa.h:296
void DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K)
Definition: dtoa.h:74
int CountDecimalDigit32(uint32_t n)
Definition: dtoa.h:48
const char * GetDigitsLut()
Definition: itoa.h:23
DiyFp GetCachedPower(int e, int *K)
Definition: diyfp.h:239
char * WriteExponent(int K, char *buffer)
Definition: dtoa.h:193
void Grisu2(double value, char *buffer, int *length, int *K)
Definition: dtoa.h:178
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1697
unsigned int uint32_t
Definition: stdint.h:126
unsigned __int64 uint64_t
Definition: stdint.h:136
Definition: diyfp.h:49
uint64_t f
Definition: diyfp.h:175
DiyFp Normalize() const
Definition: diyfp.h:111
void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const
Definition: diyfp.h:130
int e
Definition: diyfp.h:176