diff --git a/cJSON.c b/cJSON.c index 524ba46..ee2166d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -541,6 +541,15 @@ static cJSON_bool compare_double(double a, double b) 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. */ 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"); } - else if(d == (double)item->valueint) - { - length = sprintf((char*)number_buffer, "%d", item->valueint); - } + else if (d == (double)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 { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ diff --git a/tests/print_number.c b/tests/print_number.c index 3fbf9cb..89f87d5 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -72,6 +72,8 @@ static void print_number_should_print_negative_integers(void) assert_print_number("-1", -1.0); assert_print_number("-32768", -32768.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) @@ -79,6 +81,8 @@ static void print_number_should_print_positive_integers(void) assert_print_number("1", 1.0); assert_print_number("32767", 32767.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) @@ -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-126", 123e-128); assert_print_number("3.1415926535897931", 3.1415926535897931); + assert_print_number("9.10719925474099e+15", 9107199254740991.5); } 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("-1.23e+129", -123e+127); 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)