Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove traling zeroes when printing floating point numbers #123

Merged
merged 5 commits into from
Mar 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 66 additions & 31 deletions cJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,55 +324,90 @@ static void update_offset(printbuffer * const buffer)
buffer->offset += strlen((const char*)buffer_pointer);
}

/* Removes trailing zeroes from the end of a printed number */
static unsigned char *trim_trailing_zeroes(printbuffer * const buffer)
{
size_t offset = 0;
unsigned char *content = NULL;

if ((buffer == NULL) || (buffer->buffer == NULL) || (buffer->offset < 1))
{
return NULL;
}

offset = buffer->offset - 1;
content = buffer->buffer;

while ((offset > 0) && (content[offset] == '0'))
{
offset--;
}
if ((offset > 0) && (content[offset] == '.'))
{
offset--;
}

offset++;
content[offset] = '\0';

buffer->offset = offset;

return content + offset;
}

/* Render the number nicely from the given item into a string. */
static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer, const internal_hooks * const hooks)
{
unsigned char *output_pointer = NULL;
double d = item->valuedouble;
int length = 0;
cjbool trim_zeroes = true; /* should at the end be removed? */

if (output_buffer == NULL)
{
return NULL;
}

/* value is an int */
if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN))
/* This is a nice tradeoff. */
output_pointer = ensure(output_buffer, 64, hooks);
if (output_pointer != NULL)
{
/* 2^64+1 can be represented in 21 chars. */
output_pointer = ensure(output_buffer, 21, hooks);
if (output_pointer != NULL)
/* This checks for NaN and Infinity */
if ((d * 0) != 0)
{
sprintf((char*)output_pointer, "%d", item->valueint);
length = sprintf((char*)output_pointer, "null");
}
}
/* value is a floating point number */
else
{
/* This is a nice tradeoff. */
output_pointer = ensure(output_buffer, 64, hooks);
if (output_pointer != NULL)
else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
{
/* This checks for NaN and Infinity */
if ((d * 0) != 0)
{
sprintf((char*)output_pointer, "null");
}
else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
{
sprintf((char*)output_pointer, "%.0f", d);
}
else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
{
sprintf((char*)output_pointer, "%e", d);
}
else
{
sprintf((char*)output_pointer, "%f", d);
}
/* integer */
length = sprintf((char*)output_pointer, "%.0f", d);
trim_zeroes = false; /* don't remove zeroes for "big integers" */
}
else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
{
length = sprintf((char*)output_pointer, "%e", d);
trim_zeroes = false; /* don't remove zeroes in engineering notation */
}
else
{
length = sprintf((char*)output_pointer, "%f", d);
}
}

return output_pointer;
/* sprintf failed */
if (length < 0)
{
return NULL;
}

output_buffer->offset += (size_t)length;

if (trim_zeroes)
{
return trim_trailing_zeroes(output_buffer);
}

return output_buffer->buffer + output_buffer->offset;
}

/* parse 4 digit hexadecimal number */
Expand Down
6 changes: 3 additions & 3 deletions tests/inputs/test7.expected
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[{
"precision": "zip",
"Latitude": 37.766800,
"Longitude": -122.395900,
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
Expand All @@ -10,7 +10,7 @@
}, {
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Longitude": -122.02602,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
Expand Down
21 changes: 19 additions & 2 deletions tests/print_number.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static void print_number_should_print_positive_integers(void)

static void print_number_should_print_positive_reals(void)
{
assert_print_number("0.123000", 0.123);
assert_print_number("0.123", 0.123);
assert_print_number("1.000000e-09", 10e-10);
assert_print_number("1000000000000", 10e11);
assert_print_number("1.230000e+129", 123e+127);
Expand All @@ -71,7 +71,7 @@ static void print_number_should_print_positive_reals(void)

static void print_number_should_print_negative_reals(void)
{
assert_print_number("-0.012300", -0.0123);
assert_print_number("-0.0123", -0.0123);
assert_print_number("-1.000000e-09", -10e-10);
assert_print_number("-1000000000000000000000", -10e20);
assert_print_number("-1.230000e+129", -123e+127);
Expand All @@ -87,6 +87,22 @@ static void print_number_should_print_non_number(void)
/* assert_print_number("null", -INFTY); */
}

static void trim_trailing_zeroes_should_trim_trailing_zeroes(void)
{
printbuffer buffer;
unsigned char number[100];
unsigned char *pointer = NULL;
buffer.length = sizeof(number);
buffer.buffer = number;

strcpy((char*)number, "10.00");
buffer.offset = sizeof("10.00") - 1;
pointer = trim_trailing_zeroes(&buffer);
TEST_ASSERT_EQUAL_UINT8('\0', *pointer);
TEST_ASSERT_EQUAL_STRING("10", number);
TEST_ASSERT_EQUAL_UINT(sizeof("10") - 1, buffer.offset);
}

int main(void)
{
/* initialize cJSON item */
Expand All @@ -98,6 +114,7 @@ int main(void)
RUN_TEST(print_number_should_print_positive_reals);
RUN_TEST(print_number_should_print_negative_reals);
RUN_TEST(print_number_should_print_non_number);
RUN_TEST(trim_trailing_zeroes_should_trim_trailing_zeroes);

return UNITY_END();
}
2 changes: 1 addition & 1 deletion tests/print_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static void print_value_should_print_false(void)

static void print_value_should_print_number(void)
{
assert_print_value("1.500000");
assert_print_value("1.5");
}

static void print_value_should_print_string(void)
Expand Down