1 #include "absl/strings/internal/str_format/float_conversion.h"
2
3 #include <string.h>
4 #include <algorithm>
5 #include <cassert>
6 #include <cmath>
7 #include <string>
8
9 #include "absl/base/config.h"
10
11 namespace absl {
12 ABSL_NAMESPACE_BEGIN
13 namespace str_format_internal {
14
15 namespace {
16
CopyStringTo(string_view v,char * out)17 char *CopyStringTo(string_view v, char *out) {
18 std::memcpy(out, v.data(), v.size());
19 return out + v.size();
20 }
21
22 template <typename Float>
FallbackToSnprintf(const Float v,const ConversionSpec & conv,FormatSinkImpl * sink)23 bool FallbackToSnprintf(const Float v, const ConversionSpec &conv,
24 FormatSinkImpl *sink) {
25 int w = conv.width() >= 0 ? conv.width() : 0;
26 int p = conv.precision() >= 0 ? conv.precision() : -1;
27 char fmt[32];
28 {
29 char *fp = fmt;
30 *fp++ = '%';
31 fp = CopyStringTo(FormatConversionSpecImplFriend::FlagsToString(conv), fp);
32 fp = CopyStringTo("*.*", fp);
33 if (std::is_same<long double, Float>()) {
34 *fp++ = 'L';
35 }
36 *fp++ = FormatConversionCharToChar(conv.conv());
37 *fp = 0;
38 assert(fp < fmt + sizeof(fmt));
39 }
40 std::string space(512, '\0');
41 string_view result;
42 while (true) {
43 int n = snprintf(&space[0], space.size(), fmt, w, p, v);
44 if (n < 0) return false;
45 if (static_cast<size_t>(n) < space.size()) {
46 result = string_view(space.data(), n);
47 break;
48 }
49 space.resize(n + 1);
50 }
51 sink->Append(result);
52 return true;
53 }
54
55 // 128-bits in decimal: ceil(128*log(2)/log(10))
56 // or std::numeric_limits<__uint128_t>::digits10
57 constexpr int kMaxFixedPrecision = 39;
58
59 constexpr int kBufferLength = /*sign*/ 1 +
60 /*integer*/ kMaxFixedPrecision +
61 /*point*/ 1 +
62 /*fraction*/ kMaxFixedPrecision +
63 /*exponent e+123*/ 5;
64
65 struct Buffer {
push_frontabsl::str_format_internal::__anonc8c866bc0111::Buffer66 void push_front(char c) {
67 assert(begin > data);
68 *--begin = c;
69 }
push_backabsl::str_format_internal::__anonc8c866bc0111::Buffer70 void push_back(char c) {
71 assert(end < data + sizeof(data));
72 *end++ = c;
73 }
pop_backabsl::str_format_internal::__anonc8c866bc0111::Buffer74 void pop_back() {
75 assert(begin < end);
76 --end;
77 }
78
backabsl::str_format_internal::__anonc8c866bc0111::Buffer79 char &back() {
80 assert(begin < end);
81 return end[-1];
82 }
83
last_digitabsl::str_format_internal::__anonc8c866bc0111::Buffer84 char last_digit() const { return end[-1] == '.' ? end[-2] : end[-1]; }
85
sizeabsl::str_format_internal::__anonc8c866bc0111::Buffer86 int size() const { return static_cast<int>(end - begin); }
87
88 char data[kBufferLength];
89 char *begin;
90 char *end;
91 };
92
93 enum class FormatStyle { Fixed, Precision };
94
95 // If the value is Inf or Nan, print it and return true.
96 // Otherwise, return false.
97 template <typename Float>
ConvertNonNumericFloats(char sign_char,Float v,const ConversionSpec & conv,FormatSinkImpl * sink)98 bool ConvertNonNumericFloats(char sign_char, Float v,
99 const ConversionSpec &conv, FormatSinkImpl *sink) {
100 char text[4], *ptr = text;
101 if (sign_char) *ptr++ = sign_char;
102 if (std::isnan(v)) {
103 ptr = std::copy_n(FormatConversionCharIsUpper(conv.conv()) ? "NAN" : "nan",
104 3, ptr);
105 } else if (std::isinf(v)) {
106 ptr = std::copy_n(FormatConversionCharIsUpper(conv.conv()) ? "INF" : "inf",
107 3, ptr);
108 } else {
109 return false;
110 }
111
112 return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1,
113 conv.flags().left);
114 }
115
116 // Round up the last digit of the value.
117 // It will carry over and potentially overflow. 'exp' will be adjusted in that
118 // case.
119 template <FormatStyle mode>
RoundUp(Buffer * buffer,int * exp)120 void RoundUp(Buffer *buffer, int *exp) {
121 char *p = &buffer->back();
122 while (p >= buffer->begin && (*p == '9' || *p == '.')) {
123 if (*p == '9') *p = '0';
124 --p;
125 }
126
127 if (p < buffer->begin) {
128 *p = '1';
129 buffer->begin = p;
130 if (mode == FormatStyle::Precision) {
131 std::swap(p[1], p[2]); // move the .
132 ++*exp;
133 buffer->pop_back();
134 }
135 } else {
136 ++*p;
137 }
138 }
139
PrintExponent(int exp,char e,Buffer * out)140 void PrintExponent(int exp, char e, Buffer *out) {
141 out->push_back(e);
142 if (exp < 0) {
143 out->push_back('-');
144 exp = -exp;
145 } else {
146 out->push_back('+');
147 }
148 // Exponent digits.
149 if (exp > 99) {
150 out->push_back(exp / 100 + '0');
151 out->push_back(exp / 10 % 10 + '0');
152 out->push_back(exp % 10 + '0');
153 } else {
154 out->push_back(exp / 10 + '0');
155 out->push_back(exp % 10 + '0');
156 }
157 }
158
159 template <typename Float, typename Int>
CanFitMantissa()160 constexpr bool CanFitMantissa() {
161 return
162 #if defined(__clang__) && !defined(__SSE3__)
163 // Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289
164 // Casting from long double to uint64_t is miscompiled and drops bits.
165 (!std::is_same<Float, long double>::value ||
166 !std::is_same<Int, uint64_t>::value) &&
167 #endif
168 std::numeric_limits<Float>::digits <= std::numeric_limits<Int>::digits;
169 }
170
171 template <typename Float>
172 struct Decomposed {
173 Float mantissa;
174 int exponent;
175 };
176
177 // Decompose the double into an integer mantissa and an exponent.
178 template <typename Float>
Decompose(Float v)179 Decomposed<Float> Decompose(Float v) {
180 int exp;
181 Float m = std::frexp(v, &exp);
182 m = std::ldexp(m, std::numeric_limits<Float>::digits);
183 exp -= std::numeric_limits<Float>::digits;
184 return {m, exp};
185 }
186
187 // Print 'digits' as decimal.
188 // In Fixed mode, we add a '.' at the end.
189 // In Precision mode, we add a '.' after the first digit.
190 template <FormatStyle mode, typename Int>
PrintIntegralDigits(Int digits,Buffer * out)191 int PrintIntegralDigits(Int digits, Buffer *out) {
192 int printed = 0;
193 if (digits) {
194 for (; digits; digits /= 10) out->push_front(digits % 10 + '0');
195 printed = out->size();
196 if (mode == FormatStyle::Precision) {
197 out->push_front(*out->begin);
198 out->begin[1] = '.';
199 } else {
200 out->push_back('.');
201 }
202 } else if (mode == FormatStyle::Fixed) {
203 out->push_front('0');
204 out->push_back('.');
205 printed = 1;
206 }
207 return printed;
208 }
209
210 // Back out 'extra_digits' digits and round up if necessary.
RemoveExtraPrecision(int extra_digits,bool has_leftover_value,Buffer * out,int * exp_out)211 bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value,
212 Buffer *out, int *exp_out) {
213 if (extra_digits <= 0) return false;
214
215 // Back out the extra digits
216 out->end -= extra_digits;
217
218 bool needs_to_round_up = [&] {
219 // We look at the digit just past the end.
220 // There must be 'extra_digits' extra valid digits after end.
221 if (*out->end > '5') return true;
222 if (*out->end < '5') return false;
223 if (has_leftover_value || std::any_of(out->end + 1, out->end + extra_digits,
224 [](char c) { return c != '0'; }))
225 return true;
226
227 // Ends in ...50*, round to even.
228 return out->last_digit() % 2 == 1;
229 }();
230
231 if (needs_to_round_up) {
232 RoundUp<FormatStyle::Precision>(out, exp_out);
233 }
234 return true;
235 }
236
237 // Print the value into the buffer.
238 // This will not include the exponent, which will be returned in 'exp_out' for
239 // Precision mode.
240 template <typename Int, typename Float, FormatStyle mode>
FloatToBufferImpl(Int int_mantissa,int exp,int precision,Buffer * out,int * exp_out)241 bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
242 int *exp_out) {
243 assert((CanFitMantissa<Float, Int>()));
244
245 const int int_bits = std::numeric_limits<Int>::digits;
246
247 // In precision mode, we start printing one char to the right because it will
248 // also include the '.'
249 // In fixed mode we put the dot afterwards on the right.
250 out->begin = out->end =
251 out->data + 1 + kMaxFixedPrecision + (mode == FormatStyle::Precision);
252
253 if (exp >= 0) {
254 if (std::numeric_limits<Float>::digits + exp > int_bits) {
255 // The value will overflow the Int
256 return false;
257 }
258 int digits_printed = PrintIntegralDigits<mode>(int_mantissa << exp, out);
259 int digits_to_zero_pad = precision;
260 if (mode == FormatStyle::Precision) {
261 *exp_out = digits_printed - 1;
262 digits_to_zero_pad -= digits_printed - 1;
263 if (RemoveExtraPrecision(-digits_to_zero_pad, false, out, exp_out)) {
264 return true;
265 }
266 }
267 for (; digits_to_zero_pad-- > 0;) out->push_back('0');
268 return true;
269 }
270
271 exp = -exp;
272 // We need at least 4 empty bits for the next decimal digit.
273 // We will multiply by 10.
274 if (exp > int_bits - 4) return false;
275
276 const Int mask = (Int{1} << exp) - 1;
277
278 // Print the integral part first.
279 int digits_printed = PrintIntegralDigits<mode>(int_mantissa >> exp, out);
280 int_mantissa &= mask;
281
282 int fractional_count = precision;
283 if (mode == FormatStyle::Precision) {
284 if (digits_printed == 0) {
285 // Find the first non-zero digit, when in Precision mode.
286 *exp_out = 0;
287 if (int_mantissa) {
288 while (int_mantissa <= mask) {
289 int_mantissa *= 10;
290 --*exp_out;
291 }
292 }
293 out->push_front(static_cast<char>(int_mantissa >> exp) + '0');
294 out->push_back('.');
295 int_mantissa &= mask;
296 } else {
297 // We already have a digit, and a '.'
298 *exp_out = digits_printed - 1;
299 fractional_count -= *exp_out;
300 if (RemoveExtraPrecision(-fractional_count, int_mantissa != 0, out,
301 exp_out)) {
302 // If we had enough digits, return right away.
303 // The code below will try to round again otherwise.
304 return true;
305 }
306 }
307 }
308
309 auto get_next_digit = [&] {
310 int_mantissa *= 10;
311 int digit = static_cast<int>(int_mantissa >> exp);
312 int_mantissa &= mask;
313 return digit;
314 };
315
316 // Print fractional_count more digits, if available.
317 for (; fractional_count > 0; --fractional_count) {
318 out->push_back(get_next_digit() + '0');
319 }
320
321 int next_digit = get_next_digit();
322 if (next_digit > 5 ||
323 (next_digit == 5 && (int_mantissa || out->last_digit() % 2 == 1))) {
324 RoundUp<mode>(out, exp_out);
325 }
326
327 return true;
328 }
329
330 template <FormatStyle mode, typename Float>
FloatToBuffer(Decomposed<Float> decomposed,int precision,Buffer * out,int * exp)331 bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out,
332 int *exp) {
333 if (precision > kMaxFixedPrecision) return false;
334
335 // Try with uint64_t.
336 if (CanFitMantissa<Float, std::uint64_t>() &&
337 FloatToBufferImpl<std::uint64_t, Float, mode>(
338 static_cast<std::uint64_t>(decomposed.mantissa),
339 static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp))
340 return true;
341
342 #if defined(ABSL_HAVE_INTRINSIC_INT128)
343 // If that is not enough, try with __uint128_t.
344 return CanFitMantissa<Float, __uint128_t>() &&
345 FloatToBufferImpl<__uint128_t, Float, mode>(
346 static_cast<__uint128_t>(decomposed.mantissa),
347 static_cast<__uint128_t>(decomposed.exponent), precision, out,
348 exp);
349 #endif
350 return false;
351 }
352
WriteBufferToSink(char sign_char,string_view str,const ConversionSpec & conv,FormatSinkImpl * sink)353 void WriteBufferToSink(char sign_char, string_view str,
354 const ConversionSpec &conv, FormatSinkImpl *sink) {
355 int left_spaces = 0, zeros = 0, right_spaces = 0;
356 int missing_chars =
357 conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) -
358 static_cast<int>(sign_char != 0),
359 0)
360 : 0;
361 if (conv.flags().left) {
362 right_spaces = missing_chars;
363 } else if (conv.flags().zero) {
364 zeros = missing_chars;
365 } else {
366 left_spaces = missing_chars;
367 }
368
369 sink->Append(left_spaces, ' ');
370 if (sign_char) sink->Append(1, sign_char);
371 sink->Append(zeros, '0');
372 sink->Append(str);
373 sink->Append(right_spaces, ' ');
374 }
375
376 template <typename Float>
FloatToSink(const Float v,const ConversionSpec & conv,FormatSinkImpl * sink)377 bool FloatToSink(const Float v, const ConversionSpec &conv,
378 FormatSinkImpl *sink) {
379 // Print the sign or the sign column.
380 Float abs_v = v;
381 char sign_char = 0;
382 if (std::signbit(abs_v)) {
383 sign_char = '-';
384 abs_v = -abs_v;
385 } else if (conv.flags().show_pos) {
386 sign_char = '+';
387 } else if (conv.flags().sign_col) {
388 sign_char = ' ';
389 }
390
391 // Print nan/inf.
392 if (ConvertNonNumericFloats(sign_char, abs_v, conv, sink)) {
393 return true;
394 }
395
396 int precision = conv.precision() < 0 ? 6 : conv.precision();
397
398 int exp = 0;
399
400 auto decomposed = Decompose(abs_v);
401
402 Buffer buffer;
403
404 switch (conv.conv()) {
405 case ConversionChar::f:
406 case ConversionChar::F:
407 if (!FloatToBuffer<FormatStyle::Fixed>(decomposed, precision, &buffer,
408 nullptr)) {
409 return FallbackToSnprintf(v, conv, sink);
410 }
411 if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
412 break;
413
414 case ConversionChar::e:
415 case ConversionChar::E:
416 if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
417 &exp)) {
418 return FallbackToSnprintf(v, conv, sink);
419 }
420 if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
421 PrintExponent(exp, FormatConversionCharIsUpper(conv.conv()) ? 'E' : 'e',
422 &buffer);
423 break;
424
425 case ConversionChar::g:
426 case ConversionChar::G:
427 precision = std::max(0, precision - 1);
428 if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
429 &exp)) {
430 return FallbackToSnprintf(v, conv, sink);
431 }
432 if (precision + 1 > exp && exp >= -4) {
433 if (exp < 0) {
434 // Have 1.23456, needs 0.00123456
435 // Move the first digit
436 buffer.begin[1] = *buffer.begin;
437 // Add some zeros
438 for (; exp < -1; ++exp) *buffer.begin-- = '0';
439 *buffer.begin-- = '.';
440 *buffer.begin = '0';
441 } else if (exp > 0) {
442 // Have 1.23456, needs 1234.56
443 // Move the '.' exp positions to the right.
444 std::rotate(buffer.begin + 1, buffer.begin + 2,
445 buffer.begin + exp + 2);
446 }
447 exp = 0;
448 }
449 if (!conv.flags().alt) {
450 while (buffer.back() == '0') buffer.pop_back();
451 if (buffer.back() == '.') buffer.pop_back();
452 }
453 if (exp) {
454 PrintExponent(exp, FormatConversionCharIsUpper(conv.conv()) ? 'E' : 'e',
455 &buffer);
456 }
457 break;
458
459 case ConversionChar::a:
460 case ConversionChar::A:
461 return FallbackToSnprintf(v, conv, sink);
462
463 default:
464 return false;
465 }
466
467 WriteBufferToSink(sign_char,
468 string_view(buffer.begin, buffer.end - buffer.begin), conv,
469 sink);
470
471 return true;
472 }
473
474 } // namespace
475
ConvertFloatImpl(long double v,const ConversionSpec & conv,FormatSinkImpl * sink)476 bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
477 FormatSinkImpl *sink) {
478 return FloatToSink(v, conv, sink);
479 }
480
ConvertFloatImpl(float v,const ConversionSpec & conv,FormatSinkImpl * sink)481 bool ConvertFloatImpl(float v, const ConversionSpec &conv,
482 FormatSinkImpl *sink) {
483 return FloatToSink(v, conv, sink);
484 }
485
ConvertFloatImpl(double v,const ConversionSpec & conv,FormatSinkImpl * sink)486 bool ConvertFloatImpl(double v, const ConversionSpec &conv,
487 FormatSinkImpl *sink) {
488 return FloatToSink(v, conv, sink);
489 }
490
491 } // namespace str_format_internal
492 ABSL_NAMESPACE_END
493 } // namespace absl
494