From 3cd7b59a0cb068ca1ba88fd11288a6a6b089e280 Mon Sep 17 00:00:00 2001 From: dubaowei <517883875@qq.com> Date: Mon, 20 Dec 2021 19:12:58 +0800 Subject: [PATCH] print: support float pretty print Code below: float a = 0.00001; cJSON *root = cJSON_CreateObject(); cJSON_AddNumberToObject(root, "a", a); printf("%s\n", cJSON_Print(root)); Maybe it will print: { "a": 9.9999997473787516e-06 } But that's not what we really want, we want this: { "a": 1e-5 } Signed-off-by: dubaowei <517883875@qq.com> --- cJSON.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index 3063f74..7f3bb9c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -535,6 +535,11 @@ static void update_offset(printbuffer * const buffer) } /* securely comparison of floating-point variables */ +static cJSON_bool compare_float(float a, float b) +{ + float maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * FLT_EPSILON); +} static cJSON_bool compare_double(double a, double b) { double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); @@ -550,6 +555,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out size_t i = 0; unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ unsigned char decimal_point = get_decimal_point(); + float test_f = 0.0; double test = 0.0; if (output_buffer == NULL) @@ -564,14 +570,21 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out } else { - /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ - length = sprintf((char*)number_buffer, "%1.15g", d); + /* Try 7 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.7g", (float)d); /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + if ((sscanf((char*)number_buffer, "%g", &test_f) != 1) || !compare_float(test_f, (float)d)) { /* If not, print with 17 decimal places of precision */ - length = sprintf((char*)number_buffer, "%1.17g", d); + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } } }