fix: preserve numerical precision on unary negation (#3242)
This commit is contained in:
1 parent
972772153f
commit
6ce3bdf382
7 files changed
+55
-22
No files matched your search
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
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);
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user