Skip to content

Commit

Permalink
Convert decnum to binary64 (double) instead of decimal64
Browse files Browse the repository at this point in the history
This is what the JSON spec suggests and will also be less confusing compared to other jq implementations and langauges.

Related to #2939
  • Loading branch information
wader authored Nov 29, 2023
1 parent 1617091 commit 98a2069
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 16 deletions.
23 changes: 7 additions & 16 deletions src/jv.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ enum {
#define JVP_FLAGS_NUMBER_LITERAL JVP_MAKE_FLAGS(JV_KIND_NUMBER, JVP_MAKE_PFLAGS(JVP_NUMBER_DECIMAL, 1))

// the decimal precision of binary double
#define DEC_NUBMER_DOUBLE_PRECISION (16)
#define DEC_NUBMER_DOUBLE_PRECISION (17)
#define DEC_NUMBER_STRING_GUARD (14)
#define DEC_NUBMER_DOUBLE_EXTRA_UNITS ((DEC_NUBMER_DOUBLE_PRECISION - DECNUMDIGITS + DECDPUN - 1)/DECDPUN)

Expand Down Expand Up @@ -489,30 +489,22 @@ pthread_getspecific(pthread_key_t key)
#endif

static pthread_key_t dec_ctx_key;
static pthread_key_t dec_ctx_dbl_key;
static pthread_once_t dec_ctx_once = PTHREAD_ONCE_INIT;

#define DEC_CONTEXT() tsd_dec_ctx_get(&dec_ctx_key)
#define DEC_CONTEXT_TO_DOUBLE() tsd_dec_ctx_get(&dec_ctx_dbl_key)

// atexit finalizer to clean up the tsd dec contexts if main() exits
// without having called pthread_exit()
void jv_tsd_dec_ctx_fini() {
jv_mem_free(pthread_getspecific(dec_ctx_key));
jv_mem_free(pthread_getspecific(dec_ctx_dbl_key));
pthread_setspecific(dec_ctx_key, NULL);
pthread_setspecific(dec_ctx_dbl_key, NULL);
}

void jv_tsd_dec_ctx_init() {
if (pthread_key_create(&dec_ctx_key, jv_mem_free) != 0) {
fprintf(stderr, "error: cannot create thread specific key");
abort();
}
if (pthread_key_create(&dec_ctx_dbl_key, jv_mem_free) != 0) {
fprintf(stderr, "error: cannot create thread specific key");
abort();
}
atexit(jv_tsd_dec_ctx_fini);
}

Expand All @@ -533,12 +525,6 @@ static decContext* tsd_dec_ctx_get(pthread_key_t *key) {
INT32_MAX - (DECDPUN - 1) - (ctx->emax - ctx->emin - 1));
ctx->traps = 0; /*no errors*/
}
else if (key == &dec_ctx_dbl_key)
{
decContextDefault(ctx, DEC_INIT_DECIMAL64);
// just to make sure we got this right
assert(ctx->digits <= DEC_NUBMER_DOUBLE_PRECISION);
}
if (pthread_setspecific(*key, ctx) != 0) {
fprintf(stderr, "error: cannot store thread specific data");
abort();
Expand Down Expand Up @@ -610,14 +596,19 @@ static jv jvp_literal_number_new(const char * literal) {

static double jvp_literal_number_to_double(jv j) {
assert(JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL));
decContext dblCtx;

// init as decimal64 but change digits to allow conversion to binary64 (double)
decContextDefault(&dblCtx, DEC_INIT_DECIMAL64);
dblCtx.digits = DEC_NUBMER_DOUBLE_PRECISION;

decNumber *p_dec_number = jvp_dec_number_ptr(j);
decNumberDoublePrecision dec_double;
char literal[DEC_NUBMER_DOUBLE_PRECISION + DEC_NUMBER_STRING_GUARD + 1];

// reduce the number to the shortest possible form
// that fits into the 64 bit floating point representation
decNumberReduce(&dec_double.number, p_dec_number, DEC_CONTEXT_TO_DOUBLE());
decNumberReduce(&dec_double.number, p_dec_number, &dblCtx);

decNumberToString(&dec_double.number, literal);

Expand Down
9 changes: 9 additions & 0 deletions tests/jq.test
Original file line number Diff line number Diff line change
Expand Up @@ -1867,6 +1867,15 @@ false
1
1

# decnum to double conversion
.[] as $n | $n+0 | [., tostring, . == $n]
[-9007199254740993, -9007199254740992, 9007199254740992, 9007199254740993, 13911860366432393]
[-9007199254740992,"-9007199254740992",true]
[-9007199254740992,"-9007199254740992",true]
[9007199254740992,"9007199254740992",true]
[9007199254740992,"9007199254740992",true]
[13911860366432392,"13911860366432392",true]

# abs, fabs, length
abs
"abc"
Expand Down

0 comments on commit 98a2069

Please sign in to comment.