join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
dtoa.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_DATA_DTOA_HPP
26#define JOIN_DATA_DTOA_HPP
27
28// libjoin.
29#include <join/dtoapow.hpp>
30
31// C.
32#include <cassert>
33#include <cstring>
34
35namespace join
36{
37 namespace details
38 {
39 inline char* writeExponent (char* buffer, int k) noexcept
40 {
41 *buffer = '-';
42 buffer += (k < 0);
43 k = (k < 0) ? -k : k;
44 if (k >= 100)
45 {
46 *buffer++ = '0' + k / 100;
47 k %= 100;
48 *buffer++ = '0' + k / 10;
49 k %= 10;
50 }
51 else if (k >= 10)
52 {
53 *buffer++ = '0' + k / 10;
54 k %= 10;
55 }
56 *buffer++ = '0' + k;
57 return buffer;
58 }
59
60 inline char* prettify (char* buffer, int length, int k) noexcept
61 {
62 assert (length > 0);
63 const int kk = length + k;
64
65 if ((length <= kk) && (kk <= 21))
66 {
67 memset (buffer + length, '0', kk - length);
68 buffer[kk] = '.';
69 buffer[kk + 1] = '0';
70 return &buffer[kk + 2];
71 }
72 else if ((0 < kk) && (kk <= 21))
73 {
74 memmove (&buffer[kk + 1], &buffer[kk], length - kk);
75 buffer[kk] = '.';
76 return &buffer[length + 1];
77 }
78 else if ((-6 < kk) && (kk <= 0))
79 {
80 int offset = 2 - kk;
81 memmove (&buffer[offset], &buffer[0], length);
82 buffer[0] = '0';
83 buffer[1] = '.';
84 memset (&buffer[2], '0', offset - 2);
85 return &buffer[length + offset];
86 }
87 else if (length == 1)
88 {
89 buffer[1] = 'e';
90 return writeExponent (&buffer[2], kk - 1);
91 }
92 else
93 {
94 memmove (&buffer[2], &buffer[1], length - 1);
95 buffer[1] = '.';
96 buffer[length + 1] = 'e';
97 return writeExponent (&buffer[length + 2], kk - 1);
98 }
99 }
100
101 inline void grisuRound (char* buffer, int length, uint64_t delta, uint64_t rest, uint64_t ten_kappa,
102 uint64_t wp_w) noexcept
103 {
104 while ((rest < wp_w && delta - rest >= ten_kappa) &&
105 (rest + ten_kappa < wp_w || wp_w - rest > rest + ten_kappa - wp_w))
106 {
107 --buffer[length - 1];
108 rest += ten_kappa;
109 }
110 }
111
112 constexpr int digitsCount (uint32_t n) noexcept
113 {
114 if (n < 10)
115 return 1;
116 if (n < 100)
117 return 2;
118 if (n < 1000)
119 return 3;
120 if (n < 10000)
121 return 4;
122 if (n < 100000)
123 return 5;
124 if (n < 1000000)
125 return 6;
126 if (n < 10000000)
127 return 7;
128 if (n < 100000000)
129 return 8;
130 if (n < 1000000000)
131 return 9;
132 return 10;
133 }
134
135 inline void digitsGen (const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int& length,
136 int& k) noexcept
137 {
138 const DiyFp one (static_cast<uint64_t> (1) << -Mp._exponent, Mp._exponent);
139 const DiyFp wp_w = Mp - W;
140 uint32_t p1 = static_cast<uint32_t> (Mp._mantissa >> -one._exponent);
141 uint64_t p2 = Mp._mantissa & (one._mantissa - 1);
142 int kappa = digitsCount (p1);
143 length = 0;
144
145 while (kappa > 0)
146 {
147 assert (kappa >= 1 && kappa <= 10);
148 uint32_t d = p1 / pow10[kappa - 1];
149 p1 %= pow10[kappa - 1];
150 if (d || length)
151 {
152 buffer[length++] = '0' + d;
153 }
154 --kappa;
155 uint64_t tmp = (static_cast<uint64_t> (p1) << -one._exponent) + p2;
156 if (tmp <= delta)
157 {
158 k += kappa;
159 grisuRound (buffer, length, delta, tmp, static_cast<uint64_t> (pow10[kappa]) << -one._exponent,
160 wp_w._mantissa);
161 return;
162 }
163 }
164
165 uint64_t unit = 1;
166 for (;;)
167 {
168 assert (unit <= UINT64_MAX / 10);
169 p2 *= 10;
170 delta *= 10;
171 unit *= 10;
172 char d = static_cast<char> (p2 >> -one._exponent);
173 if (d || length)
174 {
175 buffer[length++] = '0' + d;
176 }
177 p2 &= one._mantissa - 1;
178 --kappa;
179 if (p2 < delta)
180 {
181 k += kappa;
182 grisuRound (buffer, length, delta, p2, one._mantissa, wp_w._mantissa * unit);
183 return;
184 }
185 }
186 }
187
188 inline void grisu2 (char* buffer, int& length, int& k, double value) noexcept
189 {
190 DiyFp val (value), minus, plus;
191 val.normalizedBoundaries (minus, plus);
192
193 const int expr = -59 - (plus._exponent + 64) + 63;
194 const int mk = (expr * 30103 + 99999) / 100000;
195
196 assert (mk + 343 >= 0 && mk + 343 < 687);
197 const DiyFp& c_mk = dtoapow[mk + 343];
198
199 minus *= c_mk;
200 plus *= c_mk;
201
202 ++minus._mantissa;
203 --plus._mantissa;
204
205 k = -mk;
206 digitsGen (val.normalize () * c_mk, plus, plus._mantissa - minus._mantissa, buffer, length, k);
207 }
208 }
209
216 inline char* dtoa (char* buffer, double value) noexcept
217 {
218 uint64_t bits;
219 memcpy (&bits, &value, sizeof (double));
220 bool is_negative = (bits >> 63) != 0;
221
222 *buffer = '-';
223 buffer += is_negative;
224 value = is_negative ? -value : value;
225
226 if (value == 0.0)
227 {
228 memcpy (buffer, "0.0", 3);
229 return buffer + 3;
230 }
231
232 int length = 0, k = 0;
233 details::grisu2 (buffer, length, k, value);
234 return details::prettify (buffer, length, k);
235 }
236}
237
238#endif
hand made floating point.
Definition diyfp.hpp:42
int _exponent
exponent.
Definition diyfp.hpp:227
uint64_t _mantissa
mantissa.
Definition diyfp.hpp:224
constexpr void normalizedBoundaries(DiyFp &minus, DiyFp &plus) const noexcept
get normalized boundaries.
Definition diyfp.hpp:148
char * prettify(char *buffer, int length, int k) noexcept
Definition dtoa.hpp:60
void digitsGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int &length, int &k) noexcept
Definition dtoa.hpp:135
constexpr int digitsCount(uint32_t n) noexcept
Definition dtoa.hpp:112
char * writeExponent(char *buffer, int k) noexcept
Definition dtoa.hpp:39
constexpr DiyFp dtoapow[]
Definition dtoapow.hpp:37
void grisu2(char *buffer, int &length, int &k, double value) noexcept
Definition dtoa.hpp:188
constexpr uint32_t pow10[]
Definition dtoapow.hpp:35
void grisuRound(char *buffer, int length, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) noexcept
Definition dtoa.hpp:101
Definition acceptor.hpp:32
char * dtoa(char *buffer, double value) noexcept
double to string conversion.
Definition dtoa.hpp:216