From b7a1201b72bf9d3c5288b4da9a920f32c4772230 Mon Sep 17 00:00:00 2001 From: itchyny Date: Tue, 4 Mar 2025 22:09:33 +0900 Subject: [PATCH] Preserve numerical precision on `length/0` (#3275) --- src/builtin.c | 2 +- src/jv.c | 15 +++++++++++++++ src/jv.h | 1 + tests/jq.test | 14 +++++++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/builtin.c b/src/builtin.c index 79d1e896..06cd213d 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -497,7 +497,7 @@ static jv f_length(jq_state *jq, jv input) { } else if (jv_get_kind(input) == JV_KIND_STRING) { return jv_number(jv_string_length_codepoints(input)); } else if (jv_get_kind(input) == JV_KIND_NUMBER) { - jv r = jv_number(fabs(jv_number_value(input))); + jv r = jv_number_abs(input); jv_free(input); return r; } else if (jv_get_kind(input) == JV_KIND_NULL) { diff --git a/src/jv.c b/src/jv.c index 4e50c582..3e9920ed 100644 --- a/src/jv.c +++ b/src/jv.c @@ -732,6 +732,21 @@ int jvp_number_is_nan(jv n) { return isnan(n.u.number); } +jv jv_number_abs(jv n) { + assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); + +#ifdef USE_DECNUM + if (JVP_HAS_FLAGS(n, JVP_FLAGS_NUMBER_LITERAL)) { + jvp_literal_number* m = jvp_literal_number_alloc(jvp_dec_number_ptr(n)->digits); + + decNumberAbs(&m->num_decimal, jvp_dec_number_ptr(n), DEC_CONTEXT()); + jv r = {JVP_FLAGS_NUMBER_LITERAL, 0, 0, 0, {&m->refcnt}}; + return r; + } +#endif + return jv_number(fabs(jv_number_value(n))); +} + jv jv_number_negate(jv n) { assert(JVP_HAS_KIND(n, JV_KIND_NUMBER)); diff --git a/src/jv.h b/src/jv.h index 5c3b7c54..5d4197cf 100644 --- a/src/jv.h +++ b/src/jv.h @@ -74,6 +74,7 @@ jv jv_number(double); jv jv_number_with_literal(const char*); double jv_number_value(jv); int jv_is_integer(jv); +jv jv_number_abs(jv); jv jv_number_negate(jv); int jv_number_has_literal(jv); diff --git a/tests/jq.test b/tests/jq.test index d5eb8dde..959895c4 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -2033,7 +2033,11 @@ map(abs) [-0, 0, -10, -1.1] [0,0,10,1.1] -map(fabs == length) | unique +map(fabs) +[-0, 0, -10, -1.1] +[0,0,10,1.1] + +map(abs == length) | unique [-10, -1.1, -1e-1, 1000000000000000002] [true] @@ -2042,6 +2046,14 @@ map(abs) [0.1,1000000000000000002] [1e-1, 1000000000000000002] +[1E+1000,-1E+1000 | abs | tojson] | unique == if have_decnum then ["1E+1000"] else ["1.7976931348623157e+308"] end +null +true + +[1E+1000,-1E+1000 | length | tojson] | unique == if have_decnum then ["1E+1000"] else ["1.7976931348623157e+308"] end +null +true + # Using a keyword as variable/label name 123 as $label | $label