libs/printf: add floating-point unit tests

This commit is contained in:
Lephe 2021-02-02 22:24:24 +01:00
parent 4350b81fc8
commit 6aa477a83a
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
2 changed files with 103 additions and 6 deletions

View File

@ -4,6 +4,7 @@
#include <gint/keyboard.h>
#include <gint/gint.h>
#include <gint/hardware.h>
#include <gint/kprint.h>
#include <gintctl/util.h>
#include <gintctl/menu.h>
@ -81,7 +82,7 @@ struct menu menu_libs = {
{ "libc: " _("TinyMT32", "TinyMT random number generation"),
gintctl_libs_tinymt, 0 },
{ "libc: " _("printf family", "Formatted printing functions"),
{ "libc: " _("printf family", "Formatted printing (with Grisu2b)"),
gintctl_libs_printf, 0 },
{ "libc: " _("mem functions", "Core memory functions"),
gintctl_libs_memory, 0 },
@ -160,6 +161,9 @@ int main(GUNUSED int isappli, GUNUSED int optnum)
/* Start the profiling library */
prof_init();
/* Enable floating-point formatters */
kprint_enable_fp();
#ifdef FX9860G
/* Use the Unicode font uf5x7 on fx-9860G */
extern font_t font_uf5x7;

View File

@ -9,19 +9,25 @@
#include <gintctl/gint.h>
#include <gintctl/util.h>
#define NAN __builtin_nan("")
#define INFINITY __builtin_inf()
#define SCROLL_HEIGHT _(8,12)
struct printf_test {
char const *format;
/* Type, argument, string, answer, passed are set by macros below */
enum { TYPE_I32, TYPE_U32, TYPE_STR, TYPE_PTR, TYPE_U64 } type;
/* Argument information is set by macros below */
enum {
TYPE_I32, TYPE_U32, TYPE_STR, TYPE_PTR, TYPE_U64, TYPE_DBL
} type;
union {
int i32;
uint32_t u32;
char const *str;
void *ptr;
uint64_t u64;
double dbl;
};
char const *argument_as_string;
char const *solution;
@ -32,6 +38,7 @@ struct printf_test {
#define STR(s) TYPE_STR, { .str = s }, #s
#define PTR(p) TYPE_PTR, { .ptr = (void *)p }, #p
#define U64(u) TYPE_U64, { .u64 = u }, #u
#define DBL(d) TYPE_DBL, { .dbl = d }, #d
static struct printf_test const tests[] = {
/* Base cases with length and precision */
@ -40,11 +47,14 @@ static struct printf_test const tests[] = {
{ "%3d", I32(65536), "65536" },
{ "%6.4d", I32(17), " 0017" },
{ "%6.3d", I32(-1876), " -1876" },
{ "%.0d", I32(0), "" },
{ "%.d", I32(0), "" },
/* Sign */
{ "%+i", I32(15), "+15" },
{ "% 7i", I32(78372), " 78372" },
{ "% d", I32(65536), " 65536" },
/* Alignment */
{ "%08d", I32(-839), "-0000839" },
{ "%-6.4d", I32(17), "0017 " },
{ "%-+6.4i", I32(17), "+0017 " },
/* Bases */
@ -66,6 +76,86 @@ static struct printf_test const tests[] = {
{ "%-8.5s", STR("Hello, World!"), "Hello " },
{ "%c", I32(100), "d" },
{ "%6c", I32('#'), " #", },
/* Floating-point special values */
{ "%f", DBL(NAN), "nan" },
{ "%3.5F", DBL(NAN), "NAN" },
{ "%+2F", DBL(-INFINITY), "-INF" },
{ "%10G", DBL(INFINITY), "INF" },
{ "%+g", DBL(INFINITY), "inf" },
{ "%7.3e", DBL(-INFINITY), "-inf" },
{ "%8E", DBL(NAN), "NAN" },
/* Simple floating-point cases */
{ "%f", DBL(13e3), "13000.000000" },
{ "%.3f", DBL(-13e3), "-13000.000" },
{ "%.F", DBL(13e3), "13000" },
{ "%f", DBL(-12.42), "-12.420000" },
{ "%.0f", DBL(-12.42), "-12", },
{ "%.1f", DBL(12.42), "12.4", },
{ "%.8F", DBL(12.42), "12.42000000" },
{ "%F", DBL(0.0312), "0.031200" },
{ "%.4f", DBL(0.0312), "0.0312" },
{ "%.2f", DBL(-0.0312), "-0.03", },
{ "%.0f", DBL(0.0312), "0", },
/* Floating-point rounding */
{ "%.f", DBL(1.75), "2", },
{ "%.1f", DBL(1.75), "1.8", },
{ "%.3F", DBL(0.0625), "0.063", },
{ "%.1F", DBL(-99.99), "-100.0" },
{ "%.2F", DBL(12999.992), "12999.99" },
{ "%.2f", DBL(12999.995), "13000.00" },
/* General options with floating-point */
{ "%09.3F", DBL(123.4567), "00123.457" },
{ "%05.0f", DBL(99.99), "00100" },
{ "%+11f", DBL(0.0035678), " +0.003568" },
{ "%- 11F", DBL(0.0035678), " 0.003568 " },
/* Simple exponent cases */
{ "%e", DBL(3.876), "3.876000e+00" },
{ "%E", DBL(-38473.34254), "-3.847334E+04" },
{ "%.2e", DBL(187.2), "1.87e+02" },
{ "%.1e", DBL(-18.27), "-1.8e+01" },
{ "%e", DBL(1e-10), "1.000000e-10" },
{ "%E", DBL(3.873e180), "3.873000E+180" },
{ "%.e", DBL(0.0005), "5e-04" },
{ "%.E", DBL(128.37), "1E+02" },
{ "%.5e", DBL(912.3), "9.12300e+02" },
/* Exponent with rounding and general options */
{ "%11.3e", DBL(12.499), " 1.250e+01" },
{ "% -11.E", DBL(358.7), " 4E+02 " },
{ "%+e", DBL(14.99999), "+1.499999e+01" },
{ "%+e", DBL(14.999999), "+1.500000e+01" },
/* Exponent sizes */
{ "%.2e", DBL(1e10), "1.00e+10" },
{ "%.2e", DBL(1e100), "1.00e+100" },
{ "%.2e", DBL(1e-10), "1.00e-10" },
{ "%.2e", DBL(1e-100), "1.00e-100" },
/* Format selection and trailing zero elimination in %g */
{ "%g", DBL(124), "124" },
{ "%g", DBL(2.3), "2.3" },
{ "%g", DBL(0.0001), "0.0001" },
{ "%G", DBL(0.00001), "1E-05" },
{ "%g", DBL(834e-93), "8.34e-91" },
{ "%g", DBL(32842914732), "3.28429e+10" },
{ "%g", DBL(123456), "123456" },
{ "%G", DBL(1234567), "1.23457E+06" },
{ "%G", DBL(123000), "123000" },
/* Rounding and general options in %g */
{ "%.3g", DBL(1278), "1.28e+03" },
{ "%+.8g", DBL(1.23e5), "+123000" },
{ "%- 12.8g", DBL(123000.01), " 123000.01 " },
{ "%0.8g", DBL(123000.001), "123000" },
{ "%08.8g", DBL(123000.001), "00123000" },
{ "%g", DBL(1.234567), "1.23457" },
{ "%.1g", DBL(1.8), "2" },
/* Edge cases of significant digit count in %g */
{ "%.4g", DBL(999.93), "999.9" },
{ "%.4g", DBL(999.97), "1000" },
{ "%.5g", DBL(999.97), "999.97" },
{ "%.8G", DBL(999.97), "999.97" },
{ "%.4g", DBL(1.0001), "1", },
/* Elimination of trailing zeros in %g */
{ "%.3g", DBL(3002), "3e+03" },
{ "%.5g", DBL(0.00000034), "3.4e-07" },
{ "%.6g", DBL(999.9997), "1000" },
/* NULL terminator */
{ NULL }
};
@ -78,7 +168,7 @@ static void run_tests(struct printf_test const *tests, char answers[][16],
struct printf_test const *t = &tests[i];
#define run(TYPE, field) case TYPE: \
snprintf(answers[i], 32, t->format, t->field); \
snprintf(answers[i], 16, t->format, t->field); \
break;
switch(t->type)
@ -88,6 +178,7 @@ static void run_tests(struct printf_test const *tests, char answers[][16],
run(TYPE_STR, str)
run(TYPE_PTR, ptr)
run(TYPE_U64, u64)
run(TYPE_DBL, dbl)
}
passed[i] = !strcmp(answers[i], t->solution);
@ -121,7 +212,8 @@ static void draw(struct printf_test const *tests, char answers[][16],
int y = (i+1) * 6;
dprint( 1, y, C_BLACK, "%d", offset+i+1);
dprint(13, y, C_BLACK, "%s", t->format);
dprint(43, y, C_BLACK, "%s", answers[offset+i]);
dprint(43, y, C_BLACK, "%s", answers[offset+i][0]
? answers[offset+i] : "<empty>");
dprint(91, y, C_BLACK, "%s", passed[offset+i]?"Ok":"Err");
}
@ -145,7 +237,8 @@ static void draw(struct printf_test const *tests, char answers[][16],
row_print(i+2, 13, "%s", t->argument_as_string);
int fg = passed[offset+i] ? C_RGB(0,31,0) : C_RGB(31,0,0);
row_print_color(i+2, 29, fg, C_NONE, "%s", answers[offset+i]);
row_print_color(i+2, 29, fg, C_NONE, "%s", answers[offset+i][0]
? answers[offset+i] : "<empty>");
}
row_print(14, 1, "Passed: %d/%d", total_passed, total);