From 98a206964d59143c6ed9189b91cdb34af1ae5071 Mon Sep 17 00:00:00 2001 From: Mattias Wadman Date: Wed, 29 Nov 2023 09:36:33 +0100 Subject: [PATCH] Convert decnum to binary64 (double) instead of decimal64 This is what the JSON spec suggests and will also be less confusing compared to other jq implementations and langauges. Related to #2939 --- src/jv.c | 23 +++++++---------------- tests/jq.test | 9 +++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/jv.c b/src/jv.c index ada15fedf9..4031dc62f4 100644 --- a/src/jv.c +++ b/src/jv.c @@ -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) @@ -489,19 +489,15 @@ 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() { @@ -509,10 +505,6 @@ void jv_tsd_dec_ctx_init() { 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); } @@ -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(); @@ -610,6 +596,11 @@ 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; @@ -617,7 +608,7 @@ static double jvp_literal_number_to_double(jv j) { // 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); diff --git a/tests/jq.test b/tests/jq.test index 9d0b59285b..c5c8cf0630 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -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"