Skip to content
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
13 changes: 7 additions & 6 deletions docs/content/manual/dev/manual.yml
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,7 @@ sections:
such `1E1234567890`, precision will be lost if the exponent
is too large.

(3) In jq programs, a leading minus sign will trigger the
conversion of the number to an IEEE754 representation.

(4) Comparisons are carried out using the untruncated
(3) Comparisons are carried out using the untruncated
big decimal representation of numbers if available, as
illustrated in one of the following examples.

Expand All @@ -395,15 +392,19 @@ sections:
input: '0.12345678901234567890123456789'
output: ['0.12345678901234567890123456789']

- program: '[., tojson] | . == if have_decnum then [12345678909876543212345,"12345678909876543212345"] else [12345678909876543000000,"12345678909876543000000"] end'
- program: '[., tojson] == if have_decnum then [12345678909876543212345,"12345678909876543212345"] else [12345678909876543000000,"12345678909876543000000"] end'
input: '12345678909876543212345'
output: ['true']

- program: '[1234567890987654321,-1234567890987654321 | tojson] == if have_decnum then ["1234567890987654321","-1234567890987654321"] else ["1234567890987654400","-1234567890987654400"] end'
input: 'null'
output: ['true']

- program: '. < 0.12345678901234567890123456788'
input: '0.12345678901234567890123456789'
output: ['false']

- program: 'map([., . == 1]) | tojson | . == if have_decnum then "[[1,true],[1.000,true],[1.0,true],[1.00,true]]" else "[[1,true],[1,true],[1,true],[1,true]]" end'
- program: 'map([., . == 1]) | tojson == if have_decnum then "[[1,true],[1.000,true],[1.0,true],[1.00,true]]" else "[[1,true],[1,true],[1,true],[1,true]]" end'
input: '[1, 1.000, 1.0, 100e-2]'
output: ['true']

Expand Down
13 changes: 7 additions & 6 deletions jq.1.prebuilt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ static jv f_negate(jq_state *jq, jv input) {
if (jv_get_kind(input) != JV_KIND_NUMBER) {
return type_error(input, "cannot be negated");
}
jv ret = jv_number(-jv_number_value(input));
jv ret = jv_number_negate(input);
jv_free(input);
return ret;
}
Expand Down
25 changes: 19 additions & 6 deletions src/jv.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,6 @@ static decNumber* jvp_dec_number_ptr(jv j) {
}

static jvp_literal_number* jvp_literal_number_alloc(unsigned literal_length) {

/* The number of units needed is ceil(DECNUMDIGITS/DECDPUN) */
int units = ((literal_length+DECDPUN-1)/DECDPUN);

Expand All @@ -571,19 +570,18 @@ static jvp_literal_number* jvp_literal_number_alloc(unsigned literal_length) {
+ sizeof(decNumberUnit) * units
);

n->refcnt = JV_REFCNT_INIT;
n->num_double = NAN;
n->literal_data = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the reson to move this from new to alloc?

Looks like jvp_literal_number_new is the only user of jvp_literal_number_alloc, maybe could be merged or keep separate for readability?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also used for negate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha sorry 👍

return n;
}

static jv jvp_literal_number_new(const char * literal) {
jvp_literal_number* n = jvp_literal_number_alloc(strlen(literal));

jvp_literal_number * n = jvp_literal_number_alloc(strlen(literal));

n->refcnt = JV_REFCNT_INIT;
n->literal_data = NULL;
decContext *ctx = DEC_CONTEXT();
decContextClearStatus(ctx, DEC_Conversion_syntax);
decNumberFromString(&n->num_decimal, literal, ctx);
n->num_double = NAN;

if (ctx->status & DEC_Conversion_syntax) {
jv_mem_free(n);
Expand Down Expand Up @@ -734,6 +732,21 @@ int jvp_number_is_nan(jv n) {
return n.u.number != n.u.number;
}

jv jv_number_negate(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);

decNumberMinus(&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(-jv_number_value(n));
}

int jvp_number_cmp(jv a, jv b) {
assert(JVP_HAS_KIND(a, JV_KIND_NUMBER));
assert(JVP_HAS_KIND(b, JV_KIND_NUMBER));
Expand Down
3 changes: 2 additions & 1 deletion src/jv.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ jv jv_number(double);
jv jv_number_with_literal(const char*);
double jv_number_value(jv);
int jv_is_integer(jv);
jv jv_number_negate(jv);

int jv_number_has_literal(jv n);
int jv_number_has_literal(jv);
const char* jv_number_get_literal(jv);

jv jv_array(void);
Expand Down
13 changes: 13 additions & 0 deletions tests/jq.test
Original file line number Diff line number Diff line change
Expand Up @@ -1985,6 +1985,19 @@ true
{"x":13911860366432393}
13911860366432382

# Unary negation preserves numerical precision
-. | tojson == if have_decnum then "-13911860366432393" else "-13911860366432392" end
13911860366432393
true

-. | tojson == if have_decnum then "0.12345678901234567890123456789" else "0.12345678901234568" end
-0.12345678901234567890123456789
true

[1E+1000,-1E+1000 | tojson] == if have_decnum then ["1E+1000","-1E+1000"] else ["1.7976931348623157e+308","-1.7976931348623157e+308"] end
null
true

. |= try . catch .
1
1
Expand Down
8 changes: 6 additions & 2 deletions tests/man.test

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading