Skip to content

Commit

Permalink
Regards #171: Adds support for long double format specifier and long …
Browse files Browse the repository at this point in the history
…double input arguments - but _not_ for internal processing of long doubles, they are down-converted to the internal representation type. Tweaked some comment text and removv ed some redundant testcases involving float-promotion relative to Yonggag Luo's original commit.

Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>
  • Loading branch information
lygstate authored and eyalroz committed Dec 9, 2023
1 parent df58e40 commit 835a48b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 20 deletions.
55 changes: 35 additions & 20 deletions src/printf/printf.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
#endif

// Support for the long long integral types (with the ll, z and t length modifiers for specifiers
// %d,%i,%o,%x,%X,%u, and with the %p specifier). Note: 'L' (long double) is not supported.
// %d,%i,%o,%x,%X,%u, and with the %p specifier).
#ifndef PRINTF_SUPPORT_LONG_LONG
#define PRINTF_SUPPORT_LONG_LONG 1
#endif
Expand Down Expand Up @@ -144,23 +144,24 @@
#define PRINTF_FLOAT_NOTATION_THRESHOLD ((floating_point_t) PRINTF_EXPAND_THEN_CONCATENATE(1e,PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL))

// internal flag definitions
#define FLAGS_ZEROPAD (1U << 0U)
#define FLAGS_LEFT (1U << 1U)
#define FLAGS_PLUS (1U << 2U)
#define FLAGS_SPACE (1U << 3U)
#define FLAGS_HASH (1U << 4U)
#define FLAGS_UPPERCASE (1U << 5U)
#define FLAGS_CHAR (1U << 6U)
#define FLAGS_SHORT (1U << 7U)
#define FLAGS_INT (1U << 8U)
#define FLAGS_ZEROPAD (1U << 0U)
#define FLAGS_LEFT (1U << 1U)
#define FLAGS_PLUS (1U << 2U)
#define FLAGS_SPACE (1U << 3U)
#define FLAGS_HASH (1U << 4U)
#define FLAGS_UPPERCASE (1U << 5U)
#define FLAGS_CHAR (1U << 6U)
#define FLAGS_SHORT (1U << 7U)
#define FLAGS_INT (1U << 8U)
// Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
#define FLAGS_LONG (1U << 9U)
#define FLAGS_LONG_LONG (1U << 10U)
#define FLAGS_PRECISION (1U << 11U)
#define FLAGS_ADAPT_EXP (1U << 12U)
#define FLAGS_POINTER (1U << 13U)
#define FLAGS_LONG (1U << 9U)
#define FLAGS_LONG_LONG (1U << 10U)
#define FLAGS_PRECISION (1U << 11U)
#define FLAGS_ADAPT_EXP (1U << 12U)
#define FLAGS_POINTER (1U << 13U)
// Note: Similar, but not identical, effect as FLAGS_HASH
#define FLAGS_SIGNED (1U << 14U)
#define FLAGS_SIGNED (1U << 14U)
#define FLAGS_LONG_DOUBLE (1U << 15U)
// Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS

#ifdef PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
Expand Down Expand Up @@ -241,6 +242,12 @@ typedef unsigned int printf_size_t;
#error "Non-binary-radix floating-point types are unsupported."
#endif

/**
* This library supports taking float-point arguments up to and including
* long double's; but - it currently does _not_ support internal
* representation and manipulation of values as long doubles; the options
* are either single-precision `float` or double-precision `double`.
*/
#if PRINTF_USE_DOUBLE_INTERNALLY
typedef double floating_point_t;
#define FP_TYPE_MANT_DIG DBL_MANT_DIG
Expand Down Expand Up @@ -1169,6 +1176,10 @@ static inline void format_string_loop(output_gadget_t* output, const char* forma
ADVANCE_IN_FORMAT_STRING(format);
}
break;
case 'L' :
flags |= FLAGS_LONG_DOUBLE;
ADVANCE_IN_FORMAT_STRING(format);
break;
case 'h' :
flags |= FLAGS_SHORT;
ADVANCE_IN_FORMAT_STRING(format);
Expand Down Expand Up @@ -1282,22 +1293,26 @@ static inline void format_string_loop(output_gadget_t* output, const char* forma
}
#if PRINTF_SUPPORT_DECIMAL_SPECIFIERS
case 'f' :
case 'F' :
case 'F' : {
floating_point_t value = (floating_point_t) (flags & FLAGS_LONG_DOUBLE ? va_arg(args, long double) : va_arg(args, double));
if (*format == 'F') flags |= FLAGS_UPPERCASE;
print_floating_point(output, (floating_point_t) va_arg(args, double), precision, width, flags, PRINTF_PREFER_DECIMAL);
print_floating_point(output, value, precision, width, flags, PRINTF_PREFER_DECIMAL);
format++;
break;
}
#endif
#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
case 'e':
case 'E':
case 'g':
case 'G':
case 'G': {
floating_point_t value = (floating_point_t) (flags & FLAGS_LONG_DOUBLE ? va_arg(args, long double) : va_arg(args, double));
if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
print_floating_point(output, (floating_point_t) va_arg(args, double), precision, width, flags, PRINTF_PREFER_EXPONENTIAL);
print_floating_point(output, value, precision, width, flags, PRINTF_PREFER_EXPONENTIAL);
format++;
break;
}
#endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
case 'c' : {
printf_size_t l = 1U;
Expand Down
31 changes: 31 additions & 0 deletions test/test_suite_main_testcases.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,17 @@ PRINTF_TEST_CASE(floating_point_specifiers_precision_and_flags)
PRINTING_CHECK("3.5", ==, sprintf_, buffer, "%.1f", 3.49);
PRINTING_CHECK("a0.5 ", ==, sprintf_, buffer, "a%-5.1f", 0.5);
PRINTING_CHECK("a0.5 end", ==, sprintf_, buffer, "a%-5.1fend", 0.5);

/* %f for double */
PRINTING_CHECK("42.895223123457", ==, sprintf_, buffer, "%.12f", 42.89522312345678);
/* %F for double */
PRINTING_CHECK("42.895223123457", ==, sprintf_, buffer, "%.12F", 42.89522312345678);
/* %lf for double */
PRINTING_CHECK("42.895223123457", ==, sprintf_, buffer, "%.12lf", 42.89522312345678);
/* %Lf for long double */
PRINTING_CHECK("42.895223123457", ==, sprintf_, buffer, "%.12Lf", 42.89522312345678l);
PRINTING_CHECK("42.895223123457", ==, sprintf_, buffer, "%.12Lf", 42.89522312345678L);

#endif
#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
PRINTING_CHECK("0.5", ==, sprintf_, buffer, "%.4g", 0.5);
Expand Down Expand Up @@ -821,6 +832,26 @@ PRINTF_TEST_CASE(floating_point_specifiers_precision_and_flags)
PRINTING_CHECK("4.895512e+04", ==, sprintf_, buffer, "%e", 48955.125);
PRINTING_CHECK("9.2524e+04", ==, sprintf_, buffer, "%.4e", 92523.5);
PRINTING_CHECK("-8.380923438e+04", ==, sprintf_, buffer, "%.9e", -83809.234375);

/* %g for double */
PRINTING_CHECK("100.", ==, sprintf_, buffer, "%#.3g", 99.998580932617187500);
/* %G for double */
PRINTING_CHECK("100.", ==, sprintf_, buffer, "%#.3G", 99.998580932617187500);
/* %lg for double */
PRINTING_CHECK("100.", ==, sprintf_, buffer, "%#.3lg", 99.998580932617187500);
/* %Lg for long double */
PRINTING_CHECK("100.", ==, sprintf_, buffer, "%#.3Lg", 99.998580932617187500l);
PRINTING_CHECK("100.", ==, sprintf_, buffer, "%#.3Lg", 99.998580932617187500L);

/* %e for double */
PRINTING_CHECK("-8.380923438e+04", ==, sprintf_, buffer, "%.9e", -83809.234375);
/* %E for double */
PRINTING_CHECK("-8.380923438E+04", ==, sprintf_, buffer, "%.9E", -83809.234375);
/* %le for double */
PRINTING_CHECK("-8.380923438e+04", ==, sprintf_, buffer, "%.9le", -83809.234375);
/* %Le for long double */
PRINTING_CHECK("-8.380923438e+04", ==, sprintf_, buffer, "%.9Le", -83809.234375l);
PRINTING_CHECK("-8.380923438e+04", ==, sprintf_, buffer, "%.9Le", -83809.234375L);
#endif
}
#endif // PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS
Expand Down

0 comments on commit 835a48b

Please sign in to comment.