Skip to content

Commit

Permalink
Regards #109: Now correctly rounding down the computed base-10 expone…
Browse files Browse the repository at this point in the history
…nt. 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.
  • Loading branch information
eyalroz committed Feb 4, 2022
1 parent 9f48faf commit 75e1769
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/printf/printf.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,16 @@ 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;
double d = (double) n;
return (d == x) ? n : n-1;
}

#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
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)
Expand All @@ -791,9 +801,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;
Expand Down
24 changes: 24 additions & 0 deletions test/test_suite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,30 @@ TEST_CASE("floating-point specifiers with 31-32 bit integer values", "[]" ) {
}
#endif

TEST_CASE("tiny floating-point values", "[]" ) {
char buffer[100];
// boltzman_s_constant = 1.380651569e-23;

#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
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", "[]" ) {
Expand Down

0 comments on commit 75e1769

Please sign in to comment.