@@ -20,9 +20,9 @@ namespace fp_formatting {
20
20
* Converts a integer into its ASCII digits.
21
21
*
22
22
* @param begin/end - a buffer, must be at least 20bytes long
23
- * @param value - input value
24
- * @param width - minimum number of digits, fill with '0' to the left. Must be equal or smaller than the buffer size.
25
- * @return - number of digits filled into the buffer.
23
+ * @param value - input value
24
+ * @param width - minimum number of digits, fill with '0' to the left. Must be equal or smaller than the buffer size.
25
+ * @return - number of digits filled into the buffer.
26
26
*
27
27
* Example:
28
28
* std::array<char, 20> buffer;
@@ -33,27 +33,27 @@ namespace fp_formatting {
33
33
* assert(buffer[2] == '3');
34
34
*/
35
35
inline auto ConvertToChars (char * begin, char * end, size_t value, int width=1 ) -> int {
36
- assert (width >= 1 );
37
- assert (end >= begin); // end must be after begin
38
- assert (end-begin >= width); // Buffer must be large enough
39
- assert (end-begin >= 20 ); // 2^64 has 20digits, so at least 20 digits must be available
40
-
41
- // count number of digits, and fill digits array accordingly
42
- int digits_ct{};
43
- while (value > 0 ) {
44
- char c = value % 10 + ' 0' ;
45
- value = value / 10 ;
46
- digits_ct += 1 ;
47
- *(end-digits_ct) = c;
48
- }
49
- while (digits_ct < width) {
50
- assert (digits_ct < 64 );
51
- digits_ct += 1 ;
52
- *(end-digits_ct) = ' 0' ;
53
- }
54
- // move data to the front of the array
55
- std::memmove (begin, end-digits_ct, digits_ct);
56
- return digits_ct;
36
+ assert (width >= 1 );
37
+ assert (end >= begin); // end must be after begin
38
+ assert (end-begin >= width); // Buffer must be large enough
39
+ assert (end-begin >= 20 ); // 2^64 has 20digits, so at least 20 digits must be available
40
+
41
+ // count number of digits, and fill digits array accordingly
42
+ int digits_ct{};
43
+ while (value > 0 ) {
44
+ char c = value % 10 + ' 0' ;
45
+ value = value / 10 ;
46
+ digits_ct += 1 ;
47
+ *(end-digits_ct) = c;
48
+ }
49
+ while (digits_ct < width) {
50
+ assert (digits_ct < 64 );
51
+ digits_ct += 1 ;
52
+ *(end-digits_ct) = ' 0' ;
53
+ }
54
+ // move data to the front of the array
55
+ std::memmove (begin, end-digits_ct, digits_ct);
56
+ return digits_ct;
57
57
}
58
58
59
59
/* *
@@ -63,144 +63,144 @@ inline auto ConvertToChars(char* begin, char* end, size_t value, int width=1) ->
63
63
*/
64
64
template <typename T>
65
65
auto FpToString (T v, int precision = 0 ) -> std::string {
66
- // assert(precision > 0);
67
- // hardcoded constant, at which exponent should switch to a scientific notation
68
- int const lowerExponentThreshold = -5 ;
69
- int const upperExponentThreshold = (precision==0 )?6 :precision;
70
- if (precision == 0 ) {
71
- precision = 6 ;
72
- }
73
-
74
- // dragonbox/to_decimal does not handle value 0, inf, NaN
75
- if (v == 0 || std::isinf (v) || std::isnan (v)) {
76
- std::stringstream ss;
77
- ss << v;
78
- return ss.str ();
79
- }
80
-
81
- auto r = jkj::dragonbox::to_decimal (v);
82
-
83
- auto digits = std::array<char , 20 >{}; // max digits of size_t is 20.
84
- auto digits_ct = ConvertToChars (digits.data (), digits.data () + digits.size (), r.significand );
85
-
86
- // check if requested precision is lower than
87
- // required digits for exact representation
88
- if (digits_ct > precision) {
89
- auto diff = digits_ct - precision;
90
- r.exponent += diff;
91
- digits_ct = precision;
92
-
93
- // round numbers if required
94
- if (digits[digits_ct] >= ' 5' ) {
95
- int i{digits_ct-1 };
96
- digits[i] += 1 ;
97
- while (digits[i] == ' 9' +1 ) {
98
- digits_ct -= 1 ;
99
- r.exponent += 1 ;
100
- if (i > 0 ) {
101
- digits[i-1 ] += 1 ;
102
- i -= 1 ;
103
- } else {
104
- digits_ct = 1 ;
105
- digits[0 ] = ' 1' ;
106
- break ;
107
- }
108
- }
66
+ // assert(precision > 0);
67
+ // hardcoded constant, at which exponent should switch to a scientific notation
68
+ int const lowerExponentThreshold = -5 ;
69
+ int const upperExponentThreshold = (precision==0 )?6 :precision;
70
+ if (precision == 0 ) {
71
+ precision = 6 ;
72
+ }
73
+
74
+ // dragonbox/to_decimal does not handle value 0, inf, NaN
75
+ if (v == 0 || std::isinf (v) || std::isnan (v)) {
76
+ std::stringstream ss;
77
+ ss << v;
78
+ return ss.str ();
79
+ }
80
+
81
+ auto r = jkj::dragonbox::to_decimal (v);
82
+
83
+ auto digits = std::array<char , 20 >{}; // max digits of size_t is 20.
84
+ auto digits_ct = ConvertToChars (digits.data (), digits.data () + digits.size (), r.significand );
85
+
86
+ // check if requested precision is lower than
87
+ // required digits for exact representation
88
+ if (digits_ct > precision) {
89
+ auto diff = digits_ct - precision;
90
+ r.exponent += diff;
91
+ digits_ct = precision;
92
+
93
+ // round numbers if required
94
+ if (digits[digits_ct] >= ' 5' ) {
95
+ int i{digits_ct-1 };
96
+ digits[i] += 1 ;
97
+ while (digits[i] == ' 9' +1 ) {
98
+ digits_ct -= 1 ;
99
+ r.exponent += 1 ;
100
+ if (i > 0 ) {
101
+ digits[i-1 ] += 1 ;
102
+ i -= 1 ;
103
+ } else {
104
+ digits_ct = 1 ;
105
+ digits[0 ] = ' 1' ;
106
+ break ;
109
107
}
108
+ }
110
109
}
111
-
112
- std::array<char , 28 > output_buffer; // max digits of size_t plus sign, a dot and 2 letters for 'e+' or 'e-' and 4 letters for the exponent
113
- auto output_ptr = &output_buffer[0 ];
114
-
115
- // print '-' symbol for negative numbers
116
- if (r.is_negative ) {
117
- *(output_ptr++) = ' -' ;
110
+ }
111
+
112
+ std::array<char , 28 > output_buffer; // max digits of size_t plus sign, a dot and 2 letters for 'e+' or 'e-' and 4 letters for the exponent
113
+ auto output_ptr = &output_buffer[0 ];
114
+
115
+ // print '-' symbol for negative numbers
116
+ if (r.is_negative ) {
117
+ *(output_ptr++) = ' -' ;
118
+ }
119
+
120
+ // exponent if only a single non-zero digit is before the decimal point
121
+ int const exponent = r.exponent + digits_ct - 1 ;
122
+
123
+ // case 1: scientific notation
124
+ if (exponent >= upperExponentThreshold || exponent <= lowerExponentThreshold) {
125
+ // print first digit
126
+ *(output_ptr++) = digits[0 ];
127
+
128
+ // print digits after decimal point
129
+ if (digits_ct > 1 ) {
130
+ *(output_ptr++) = ' .' ;
131
+ // print significant numbers after decimal point
132
+ for (int i{1 }; i < digits_ct; ++i) {
133
+ *(output_ptr++) = digits[i];
134
+ }
135
+ }
136
+ *(output_ptr++) = ' e' ;
137
+ *(output_ptr++) = (exponent>=0 )?' +' :' -' ;
138
+ auto exp_digits = std::array<char , 20 >{};
139
+ auto exp_digits_ct = ConvertToChars (exp_digits.data (), exp_digits.data () + exp_digits.size (), std::abs (exponent), /* .precision=*/ 2 );
140
+ for (int i{0 }; i < exp_digits_ct; ++i) {
141
+ *(output_ptr++) = exp_digits[i];
118
142
}
119
143
120
- // exponent if only a single non-zero digit is before the decimal point
121
- int const exponent = r.exponent + digits_ct - 1 ;
122
-
123
- // case 1: scientific notation
124
- if (exponent >= upperExponentThreshold || exponent <= lowerExponentThreshold) {
125
- // print first digit
126
- *(output_ptr++) = digits[0 ];
127
-
128
- // print digits after decimal point
129
- if (digits_ct > 1 ) {
130
- *(output_ptr++) = ' .' ;
131
- // print significant numbers after decimal point
132
- for (int i{1 }; i < digits_ct; ++i) {
133
- *(output_ptr++) = digits[i];
134
- }
135
- }
136
- *(output_ptr++) = ' e' ;
137
- *(output_ptr++) = (exponent>=0 )?' +' :' -' ;
138
- auto exp_digits = std::array<char , 20 >{};
139
- auto exp_digits_ct = ConvertToChars (exp_digits.data (), exp_digits.data () + exp_digits.size (), std::abs (exponent), /* .precision=*/ 2 );
140
- for (int i{0 }; i < exp_digits_ct; ++i) {
141
- *(output_ptr++) = exp_digits[i];
142
- }
143
-
144
- // case 2: default notation
144
+ // case 2: default notation
145
+ } else {
146
+ auto const digits_end = digits.begin () + digits_ct;
147
+ auto digits_iter = digits.begin ();
148
+
149
+ // print digits before point
150
+ int const before_decimal_digits = digits_ct + r.exponent ;
151
+ if (before_decimal_digits > 0 ) {
152
+ // print digits before point
153
+ for (int i{0 }; i < std::min (before_decimal_digits, digits_ct); ++i) {
154
+ *(output_ptr++) = *(digits_iter++);
155
+ }
156
+ // print trailing zeros before point
157
+ for (int i{0 }; i < before_decimal_digits - digits_ct; ++i) {
158
+ *(output_ptr++) = ' 0' ;
159
+ }
160
+
161
+ // print 0 before point if none where printed before
145
162
} else {
146
- auto const digits_end = digits.begin () + digits_ct;
147
- auto digits_iter = digits.begin ();
148
-
149
- // print digits before point
150
- int const before_decimal_digits = digits_ct + r.exponent ;
151
- if (before_decimal_digits > 0 ) {
152
- // print digits before point
153
- for (int i{0 }; i < std::min (before_decimal_digits, digits_ct); ++i) {
154
- *(output_ptr++) = *(digits_iter++);
155
- }
156
- // print trailing zeros before point
157
- for (int i{0 }; i < before_decimal_digits - digits_ct; ++i) {
158
- *(output_ptr++) = ' 0' ;
159
- }
160
-
161
- // print 0 before point if none where printed before
162
- } else {
163
- *(output_ptr++) = ' 0' ;
164
- }
163
+ *(output_ptr++) = ' 0' ;
164
+ }
165
165
166
- if (digits_iter != digits_end) {
167
- *(output_ptr++) = ' .' ;
168
- // print 0 afer decimal point, to fill until first digits
169
- int const after_decimal_zeros = -digits_ct - r.exponent ;
170
- for (int i{0 }; i < after_decimal_zeros; ++i) {
171
- *(output_ptr++) = ' 0' ;
172
- }
173
-
174
- // print significant numbers after decimal point
175
- for (;digits_iter < digits_end; ++digits_iter) {
176
- *(output_ptr++) = *digits_iter;
177
- }
178
- }
166
+ if (digits_iter != digits_end) {
167
+ *(output_ptr++) = ' .' ;
168
+ // print 0 afer decimal point, to fill until first digits
169
+ int const after_decimal_zeros = -digits_ct - r.exponent ;
170
+ for (int i{0 }; i < after_decimal_zeros; ++i) {
171
+ *(output_ptr++) = ' 0' ;
172
+ }
173
+
174
+ // print significant numbers after decimal point
175
+ for (;digits_iter < digits_end; ++digits_iter) {
176
+ *(output_ptr++) = *digits_iter;
177
+ }
179
178
}
180
- *output_ptr = ' \0 ' ;
181
- return std::string{&output_buffer[0 ], output_ptr};
179
+ }
180
+ *output_ptr = ' \0 ' ;
181
+ return std::string{&output_buffer[0 ], output_ptr};
182
182
}
183
183
184
184
}
185
185
}
186
186
187
187
inline auto FpToString (float v, size_t precision = 0 ) -> std::string {
188
- return detail::fp_formatting::FpToString (v, precision);
188
+ return detail::fp_formatting::FpToString (v, precision);
189
189
}
190
190
191
191
inline auto FpToString (double v, size_t precision = 0 ) -> std::string {
192
- return detail::fp_formatting::FpToString (v, precision);
192
+ return detail::fp_formatting::FpToString (v, precision);
193
193
}
194
194
195
195
/* *
196
196
* dragonbox only works for floats/doubles not long double
197
197
*/
198
198
inline auto FpToString (long double v, size_t precision = std::numeric_limits<long double >::max_digits10) -> std::string {
199
- std::stringstream ss;
200
- ss.precision (precision );
201
- ss.imbue ( std::locale ( " C " ) );
202
- ss << v;
203
- return ss.str ();
199
+ std::stringstream ss;
200
+ ss.imbue ( std::locale ( " C " ) );
201
+ ss.precision (precision );
202
+ ss << v;
203
+ return ss.str ();
204
204
}
205
205
206
206
}
0 commit comments