Jeff on Gmail
unread,Oct 24, 2022, 8:53:28 PM10/24/22Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Jansson users
I'm running Jansson 14 on macOS 16.0 with Xcode 14.0 on an x86 Mac. I've run into a bizarre issue for the json_dump*() functions where some simple real numbers aren't "rounded" correctly on output. Most numbers are fine. For example 1963.3 is indeed displayed as "1963.3". However, there are a few strange ones. For example, 1963.4 is dumped as "1963.4000000000001".
I snooped around the Jansson source and found the strconv.c file with the jsonp_dtostr() function. I did not know about the "%.*g" format available available for the *printf(3) standard library functions that allow a maximum precision to be specified with floating point numbers. That's kind of cool! The code agrees with the Jansson encoding documentation with the JSON_REAL_PRECISION(n) flag. The default precision is 17 which apparently agrees with the IEEE 754 specification. I glanced at IEEE 754, but it was mostly over my head!
Anyway, for my project, I can simply specify a precision of 16 and get the output I expect. Outside of Jansson, I can use long double instead of double to avoid the issue.
I'm curious if anyone else has seen something like this. I don't think this a Jansson bug. I'm wondering if this could be an OS or compiler or standard library or IEEE 754 issue. I've been too lazy to try this on another platform! Here's a simple program to demonstrate the issue both with and without Jansson:
#include <stdio.h>
#include <string.h>
#include <jansson.h>
int
main(int argc, char **argv)
{
const long double ldvalue = 1963.4L;
const double dvalue =1963.4;
const double dvaluex = 1963.3;
json_t *js_obj = json_object();
json_object_set_new(js_obj, "value", json_real(dvalue));
printf("json_dumpf with value %0.1lf with default precision 17\n ", dvalue);
json_dumpf(js_obj, stdout, 0);
printf("\n");
printf("json_dumpf with value %0.1lf with precision 16\n ", dvalue);
json_dumpf(js_obj, stdout, JSON_REAL_PRECISION(16));
printf("\n");
printf("printf of double value %0.1lf with precision 17\n %.*g\n", dvalue, 17, dvalue);
printf("printf of double value %0.1lf with precision 16\n %.*g\n", dvalue, 16, dvalue);
printf("printf of long double value %0.1Lf with precision 17\n %.*Lg\n", ldvalue, 17, ldvalue);
json_object_set_new(js_obj, "valuex", json_real(dvaluex));
printf("json_dumpf with valuex %0.1lf with default precision 17\n ", dvaluex);
json_dumpf(js_obj, stdout, 0);
printf("\n");
exit(0);
}
And here's the output:
json_dumpf with value 1963.4 with default precision 17
{"value": 1963.4000000000001}
json_dumpf with value 1963.4 with precision 16
{"value": 1963.4}
printf of double value 1963.4 with precision 17
1963.4000000000001
printf of double value 1963.4 with precision 16
1963.4
printf of long double value 1963.4 with precision 17
1963.4
json_dumpf with valuex 1963.3 with default precision 17
{"value": 1963.4000000000001, "valuex": 1963.3}
Anyone want to try it with your favorite platform?
Jeff