Fix an issue where 16-digit integers ending with 0

are printed in exponential format
This commit is contained in:
Hironobu Ishii 2023-05-08 22:49:20 +09:00
parent f0232f21bd
commit decce2ce6f
2 changed files with 26 additions and 4 deletions

24
cJSON.c
View File

@ -541,6 +541,15 @@ static cJSON_bool compare_double(double a, double b)
return (fabs(a - b) <= maxVal * DBL_EPSILON); return (fabs(a - b) <= maxVal * DBL_EPSILON);
} }
/* check if the double value is in the range [-(2^53-1), 2^53-1] and has no fractional part */
#define Number_MAX_SAFE_INTEGER (9007199254740991.0) /* 2^53-1 (double constant) */
static cJSON_bool is_safe_integer(double d)
{
double abs_d = fabs(d);
double trunc_d = d >= 0 ? floor(d) : -floor(-d);
return (abs_d <= Number_MAX_SAFE_INTEGER && (fabs(d - trunc_d) <= abs_d * DBL_EPSILON));
}
/* Render the number nicely from the given item into a string. */ /* Render the number nicely from the given item into a string. */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{ {
@ -562,10 +571,17 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
{ {
length = sprintf((char*)number_buffer, "null"); length = sprintf((char*)number_buffer, "null");
} }
else if(d == (double)item->valueint) else if (d == (double)item->valueint)
{ {
length = sprintf((char*)number_buffer, "%d", item->valueint); length = sprintf((char*)number_buffer, "%d", item->valueint);
} }
else if (is_safe_integer(d))
{
/* Avoid exponential expression in case of integer between
* Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER
*/
length = sprintf((char*)number_buffer, "%.0f", d);
}
else else
{ {
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */

View File

@ -72,6 +72,8 @@ static void print_number_should_print_negative_integers(void)
assert_print_number("-1", -1.0); assert_print_number("-1", -1.0);
assert_print_number("-32768", -32768.0); assert_print_number("-32768", -32768.0);
assert_print_number("-2147483648", -2147483648.0); assert_print_number("-2147483648", -2147483648.0);
assert_print_number("-9007199254740990", -9007199254740990.0);
assert_print_number("-9007199254740991", -9007199254740991.0);
} }
static void print_number_should_print_positive_integers(void) static void print_number_should_print_positive_integers(void)
@ -79,6 +81,8 @@ static void print_number_should_print_positive_integers(void)
assert_print_number("1", 1.0); assert_print_number("1", 1.0);
assert_print_number("32767", 32767.0); assert_print_number("32767", 32767.0);
assert_print_number("2147483647", 2147483647.0); assert_print_number("2147483647", 2147483647.0);
assert_print_number("9007199254740990", 9007199254740990.0);
assert_print_number("9007199254740991", 9007199254740991.0);
} }
static void print_number_should_print_positive_reals(void) static void print_number_should_print_positive_reals(void)
@ -89,6 +93,7 @@ static void print_number_should_print_positive_reals(void)
assert_print_number("1.23e+129", 123e+127); assert_print_number("1.23e+129", 123e+127);
assert_print_number("1.23e-126", 123e-128); assert_print_number("1.23e-126", 123e-128);
assert_print_number("3.1415926535897931", 3.1415926535897931); assert_print_number("3.1415926535897931", 3.1415926535897931);
assert_print_number("9.10719925474099e+15", 9107199254740991.5);
} }
static void print_number_should_print_negative_reals(void) static void print_number_should_print_negative_reals(void)
@ -98,6 +103,7 @@ static void print_number_should_print_negative_reals(void)
assert_print_number("-1e+21", -10e20); assert_print_number("-1e+21", -10e20);
assert_print_number("-1.23e+129", -123e+127); assert_print_number("-1.23e+129", -123e+127);
assert_print_number("-1.23e-126", -123e-128); assert_print_number("-1.23e-126", -123e-128);
assert_print_number("-9.10719925474099e+15", -9107199254740991.5);
} }
static void print_number_should_print_non_number(void) static void print_number_should_print_non_number(void)