FastLED 3.10.6
Loading...
Searching...
No Matches

◆ format_float()

fl::string fl::printf_detail::format_float ( float value,
int precision )
inline

Definition at line 341 of file stdio.h.

341 {
342 // Non-finite first. These used to reach the integer cast below and print
343 // as `-21474836.48` -- a plausible-looking number for a value that is not
344 // a number at all.
345 if (value != value) {
346 return fl::string("nan");
347 }
348 if (!float_is_finite(value)) {
349 return fl::string(value < 0.0f ? "-inf" : "inf");
350 }
351
352 if (precision < 0) {
353 // Default precision - use sstream's default behavior
354 sstream stream;
355 stream << value;
356 return stream.str();
357 }
358
359 // Past what an integer accumulator can hold, digit-by-digit rendering is
360 // not available at all, so say so in a different shape rather than
361 // printing a wrong number.
363 return format_float_scientific(value, precision > 0 ? precision : 6);
364 }
365
366 const bool negative = value < 0.0f;
367 const float magnitude = negative ? -value : value;
368
369 // Split before scaling, not after. Multiplying the whole value by the
370 // multiplier in float loses the low digits of a large integer part -- 1e9
371 // at precision 2 came out as 999999979.52, because 1e11 is not
372 // representable in a float. Only the fractional residue is scaled; the
373 // integer part goes through as an integer.
374 //
375 // Above 2^24 a float has no fractional part, so the residue is exactly
376 // zero there and the clamp below is for the rounding of the cast back,
377 // not for a value that genuinely has digits to lose.
378 fl::i64 int_part = static_cast<fl::i64>(magnitude);
379 float residue = magnitude - static_cast<float>(int_part);
380 if (residue < 0.0f) {
381 residue = 0.0f;
382 }
383
384 if (precision == 0) {
385 if (residue >= 0.5f) {
386 ++int_part;
387 }
388 sstream stream;
389 if (negative && int_part != 0) {
390 stream << "-";
391 }
392 stream << int_part;
393 return stream.str();
394 }
395
396 fl::i64 multiplier = 1;
397 for (int i = 0; i < precision; ++i) {
398 multiplier *= 10;
399 }
400
401 fl::i64 frac_part =
402 static_cast<fl::i64>(residue * static_cast<float>(multiplier) + 0.5f);
403 if (frac_part >= multiplier) {
404 // Rounded up through the next whole unit.
405 frac_part -= multiplier;
406 ++int_part;
407 }
408
409 sstream stream;
410 // The sign is printed from the sign of the input, not recovered from the
411 // integer part, so -0.5 keeps its sign at precision 1.
412 if (negative && (int_part != 0 || frac_part != 0)) {
413 stream << "-";
414 }
415 stream << int_part;
416 stream << ".";
417
418 // Emit exactly `precision` fractional digits, zero-padded on the left.
419 // The previous implementation stopped padding once temp_multiplier dropped
420 // to 1, which produced "0.0"/"1.0" instead of "0.00"/"1.00" for any
421 // integer-valued input. It also omitted the digits entirely when
422 // frac_part == 0.
423 fl::i64 temp_multiplier = multiplier / 10;
424 while (temp_multiplier > 0) {
425 const fl::i64 digit = (frac_part / temp_multiplier) % 10;
426 stream << static_cast<char>('0' + static_cast<int>(digit));
427 temp_multiplier /= 10;
428 }
429
430 return stream.str();
431}
constexpr float kFloatDecimalLimit
Definition stdio.h:311
bool float_is_finite(float value) FL_NO_EXCEPT
Definition stdio.cpp.hpp:6
fl::string format_float_scientific(float value, int precision) FL_NO_EXCEPT
Definition stdio.cpp.hpp:15
constexpr int type_rank< T >::value

References fl::FL_NO_EXCEPT, float_is_finite(), format_float_scientific(), kFloatDecimalLimit, fl::sstream::str(), and fl::type_rank< T >::value.

Referenced by format_arg(), format_float_scientific(), format_floating(), and fl::ftoa().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: