Skip to content
Open
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS)
/W4
/wd4001
/D_CRT_SECURE_NO_WARNINGS
/utf-8
)
endif()
endif()
Expand Down
16 changes: 16 additions & 0 deletions cJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,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 ((double)9007199254740991.0) /* 2^53-1 */
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)
{
Expand All @@ -617,6 +626,13 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
{
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 */
Expand Down
6 changes: 6 additions & 0 deletions tests/print_number.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,17 @@ 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)
{
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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down