From cf3182021a3a76b753c2ad04aea85058abb0756f Mon Sep 17 00:00:00 2001 From: Graham Sanderson Date: Thu, 25 Feb 2021 10:00:05 -0600 Subject: [PATCH] %g should not print 0 as infe-308 (#185) --- src/rp2_common/pico_printf/printf.c | 38 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/rp2_common/pico_printf/printf.c b/src/rp2_common/pico_printf/printf.c index fde2980..69655e9 100644 --- a/src/rp2_common/pico_printf/printf.c +++ b/src/rp2_common/pico_printf/printf.c @@ -490,21 +490,27 @@ static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, d } conv; conv.F = value; - int exp2 = (int) ((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 - conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) - // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 - int expval = (int) (0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); - // now we want to compute 10^expval but we want to be sure it won't overflow - exp2 = (int) (expval * 3.321928094887362 + 0.5); - const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; - const double z2 = z * z; - conv.U = (uint64_t) (exp2 + 1023) << 52U; - // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex - conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); - // correct for rounding errors - if (value < conv.F) { - expval--; - conv.F /= 10; + int expval; + if (conv.U) { + int exp2 = (int) ((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + expval = (int) (0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int) (expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t) (exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + } else { + expval = 0; + conv.F = 1; } // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters @@ -513,7 +519,7 @@ static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, d // in "%g" mode, "prec" is the number of *significant figures* not decimals if (flags & FLAGS_ADAPT_EXP) { // do we want to fall-back to "%f" mode? - if ((value >= 1e-4) && (value < 1e6)) { + if ((value == 0.0) || ((value >= 1e-4) && (value < 1e6))) { if ((int) prec > expval) { prec = (unsigned) ((int) prec - expval - 1); } else {