From bbe442f90e17d2c66f1dc349a8ff377ece71c29d Mon Sep 17 00:00:00 2001 From: Eyal Rozenberg Date: Fri, 4 Feb 2022 17:51:48 +0200 Subject: [PATCH] Regards #109: Now correctly rounding down the computed base-10 exponent. CAVEAT: This exposes an issue with printing values having exponent -308 (the minimum exponent for double's); and - we see some divergence from perfect corrtness with higher precision values. --- src/printf/printf.c | 15 +++++++++++++-- test/test_suite.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/printf/printf.c b/src/printf/printf.c index c48c666c..42aeeecd 100644 --- a/src/printf/printf.c +++ b/src/printf/printf.c @@ -765,6 +765,15 @@ static void print_decimal_number(output_gadget_t* output, double number, printf_ print_broken_up_decimal(value_, output, precision, width, flags, buf, len); } +// A floor function - but one which only works for numbers whose +// floor value is representable by an int. +static int bastardized_floor(double x) +{ + if (x >= 0) { return (int) x; } + int n = (int) x; + return ( ((double) n) == x ) ? n : n-1; +} + #if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS // internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse static void print_exponential_number(output_gadget_t* output, double number, printf_size_t precision, printf_size_t width, printf_flags_t flags, char* buf, printf_size_t len) @@ -791,9 +800,11 @@ static void print_exponential_number(output_gadget_t* output, double number, pri // drop the exponent, so conv.F comes into the range [1,2) conv.U = (conv.U & (( (double_uint_t)(1) << DOUBLE_STORED_MANTISSA_BITS) - 1U)) | ((double_uint_t) DOUBLE_BASE_EXPONENT << DOUBLE_STORED_MANTISSA_BITS); // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 - exp10 = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + double exp10_ = (0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + + exp10 = bastardized_floor(exp10_); // now we want to compute 10^exp10 but we want to be sure it won't overflow - exp2 = (int)(exp10 * 3.321928094887362 + 0.5); + exp2 = bastardized_floor(exp10 * 3.321928094887362 + 0.5); const double z = exp10 * 2.302585092994046 - exp2 * 0.6931471805599453; const double z2 = z * z; conv.U = ((double_uint_t)(exp2) + DOUBLE_BASE_EXPONENT) << DOUBLE_STORED_MANTISSA_BITS; diff --git a/test/test_suite.cpp b/test/test_suite.cpp index 1645fc4c..2fd32b83 100644 --- a/test/test_suite.cpp +++ b/test/test_suite.cpp @@ -873,6 +873,30 @@ TEST_CASE("floating-point specifiers with 31-32 bit integer values", "[]" ) { } #endif +#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS +TEST_CASE("tiny floating-point values", "[]" ) { + char buffer[100]; +// boltzman_s_constant = 1.380651569e-23; + + PRINTING_CHECK("1e-23", ==, sprintf_, buffer, "%.0e", 1.380651569e-23); + PRINTING_CHECK("1.4e-23", ==, sprintf_, buffer, "%.1e", 1.380651569e-23); + PRINTING_CHECK("1.38e-23", ==, sprintf_, buffer, "%.2e", 1.380651569e-23); + PRINTING_CHECK("1.381e-23", ==, sprintf_, buffer, "%.3e", 1.380651569e-23); + PRINTING_CHECK("1.3807e-23", ==, sprintf_, buffer, "%.4e", 1.380651569e-23); + PRINTING_CHECK("1.38065e-23", ==, sprintf_, buffer, "%.5e", 1.380651569e-23); + PRINTING_CHECK("1.380652e-23", ==, sprintf_, buffer, "%.6e", 1.380651569e-23); + PRINTING_CHECK("1.3806516e-23", ==, sprintf_, buffer, "%.7e", 1.380651569e-23); + PRINTING_CHECK("1.38065157e-23", ==, sprintf_, buffer, "%.8e", 1.380651569e-23); + PRINTING_CHECK("1.380651569e-23", ==, sprintf_, buffer, "%.9e", 1.380651569e-23); + PRINTING_CHECK("1.3806515690e-23", ==, sprintf_, buffer, "%.10e", 1.380651569e-23); + PRINTING_CHECK("1.38065156900e-23", ==, sprintf_, buffer, "%.11e", 1.380651569e-23); + PRINTING_CHECK("1.380651569000e-23", ==, sprintf_, buffer, "%.12e", 1.380651569e-23); + PRINTING_CHECK("1.3806515690000e-23", ==, sprintf_, buffer, "%.13e", 1.380651569e-23); + PRINTING_CHECK("1.38065156900000e-23", ==, sprintf_, buffer, "%.14e", 1.380651569e-23); + PRINTING_CHECK("1.380651569000000e-23", ==, sprintf_, buffer, "%.15e", 1.380651569e-23); + PRINTING_CHECK("1.3806515690000000e-23", ==, sprintf_, buffer, "%.16e", 1.380651569e-23); +} +#endif #if PRINTF_SUPPORT_DECIMAL_SPECIFIERS TEST_CASE("fallback from decimal to exponential", "[]" ) {