From a8927bf27b57a1f49d525f628a97de9c1fce710b Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 26 Nov 2014 17:26:58 +0000 Subject: 33793: add 0b binary interpretation to integer constants --- Src/math.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Src/math.c') diff --git a/Src/math.c b/Src/math.c index 266569827..438a17089 100644 --- a/Src/math.c +++ b/Src/math.c @@ -449,12 +449,14 @@ lexconstant(void) nptr++; if (*nptr == '0') { + int lowchar; nptr++; - if (*nptr == 'x' || *nptr == 'X') { + lowchar = tolower(*nptr); + if (lowchar == 'x' || lowchar == 'b') { /* Let zstrtol parse number with base */ yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1); /* Should we set lastbase here? */ - lastbase = 16; + lastbase = (lowchar == 'b') ? 2 : 16; if (isset(FORCEFLOAT)) { yyval.type = MN_FLOAT; -- cgit v1.2.3 From 39a6e8a7f5eebc337f47f88a95696140d63f2e2d Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 11 Jan 2015 11:29:17 -0800 Subject: 34230: call fmod() for modulo with floats --- ChangeLog | 4 ++++ Src/math.c | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'Src/math.c') diff --git a/ChangeLog b/ChangeLog index 59c4d62b0..a963399c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2015-01-11 Barton E. Schaefer + + * 34230: Src/math.c: call fmod() for modulo with floats + 2015-01-11 Peter Stephenson * 34234: Src/lex.c, Src/zsh.h: use structures for normal and raw diff --git a/Src/math.c b/Src/math.c index 438a17089..6d096e0df 100644 --- a/Src/math.c +++ b/Src/math.c @@ -288,11 +288,11 @@ static int type[TOKCOUNT] = { /* 0 */ LR, LR|OP_OP|OP_OPF, RL, RL, RL|OP_OP|OP_OPF, /* 5 */ RL|OP_OP|OP_OPF, RL, RL, LR|OP_A2IO, LR|OP_A2IO, -/* 10 */ LR|OP_A2IO, LR|OP_A2, LR|OP_A2, LR|OP_A2IO, LR|OP_A2, +/* 10 */ LR|OP_A2IO, LR|OP_A2, LR|OP_A2, LR|OP_A2, LR|OP_A2, /* 15 */ LR|OP_A2, LR|OP_A2IO, LR|OP_A2IO, LR|OP_A2IR, LR|OP_A2IR, /* 20 */ LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, BOOL|OP_A2IO, /* 25 */ BOOL|OP_A2IO, LR|OP_A2IO, RL|OP_OP, RL|OP_OP, RL|OP_E2, -/* 30 */ RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2IO, +/* 30 */ RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2, /* 35 */ RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, /* 40 */ BOOL|OP_E2IO, BOOL|OP_E2IO, RL|OP_A2IO, RL|OP_A2, RL|OP_OP, /* 45 */ RL, RL, LR|OP_OPF, LR|OP_OPF, RL|OP_A2, @@ -1133,7 +1133,9 @@ op(int what) * Any integer mod -1 is the same as any integer mod 1 * i.e. zero. */ - if (b.u.l == -1) + if (c.type == MN_FLOAT) + c.u.d = fmod(a.u.d, b.u.d); + else if (b.u.l == -1) c.u.l = 0; else c.u.l = a.u.l % b.u.l; -- cgit v1.2.3 From 5f4325a0a41987a92cee8b64a76e5b0d5e831f60 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 12 Jan 2015 16:38:00 +0000 Subject: Propagate float/integer type in arithmetic assignment. Add test. Mention this and also floating point mod change in README. --- ChangeLog | 3 +++ README | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ Src/math.c | 29 ++++++++++++++++++++++++++++- Test/C01arith.ztst | 10 +++++++++- 4 files changed, 88 insertions(+), 2 deletions(-) (limited to 'Src/math.c') diff --git a/ChangeLog b/ChangeLog index a9a44a379..4c29d89ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-01-12 Peter Stephenson + * 34255: README, Src/math.c, Test/C01arith.ztst: propagate type + from variable assignment. Also note 34230 in README. + * 34253: Doc/Zsh/contrib.yo: warning on integer arithmetic for zcalc, c.f. 34194. diff --git a/README b/README index e3ccc70b1..218f27d58 100644 --- a/README +++ b/README @@ -35,6 +35,54 @@ Zsh is a shell with lots of features. For a list of some of these, see the file FEATURES, and for the latest changes see NEWS. For more details, see the documentation. +Incompatibilites between 5.0.7 and 5.0.8 +---------------------------------------- + +A couple of arithmetic operations have changed: the new behaviour +is intended to be more consistent, but is not compatible with the old. + +Previously, the modulus operation, `%', implicitly converted the +operation to integer and output an integer result, even if one +or both of the arguments were floating point. Now, the C math +library fmod() operator is used to implement the operation where +one of the arguments is floating point. For example: + +Old behavour: + +% print $(( 5.5 % 2 )) +1 + +New behaviour: + +% print $(( 5.5 % 2 )) +1.5 + +Previously, assignments to variables assigned the correct type to +variables declared as floating point or integer, but this type was +not propagated to the value of the expression, as a C programmer +would naturally expect. Now, the type of the variable is propagated +so long as the variable is declared as a numeric type (however this +happened, e.g. the variable may have been implicitly typed by a +previous assignment). For example: + +Old behaviour: + +% integer var +% print $(( var = 5.5 / 2.0 )) +2.2000000000000002 +% print $var +2 + +(the actual rounding error may vary). + +New behaviour: + +% integer var +% print $(( var = 5.5 / 2.0 )) +2 +% print $var +2 + Incompatibilities between 5.0.2 and 5.0.5 ----------------------------------------- diff --git a/Src/math.c b/Src/math.c index 6d096e0df..db42d0f7c 100644 --- a/Src/math.c +++ b/Src/math.c @@ -880,6 +880,8 @@ getcvar(char *s) static mnumber setmathvar(struct mathvalue *mvp, mnumber v) { + Param pm; + if (mvp->pval) { /* * This value may have been hanging around for a while. @@ -909,7 +911,32 @@ setmathvar(struct mathvalue *mvp, mnumber v) if (noeval) return v; untokenize(mvp->lval); - setnparam(mvp->lval, v); + pm = setnparam(mvp->lval, v); + if (pm) { + /* + * If we are performing an assignment, we return the + * number with the same type as the parameter we are + * assigning to, in the spirit of the way assignments + * in C work. Note this was a change to long-standing + * zsh behaviour. + */ + switch (PM_TYPE(pm->node.flags)) { + case PM_INTEGER: + if (v.type != MN_INTEGER) { + v.u.l = (zlong)v.u.d; + v.type = MN_INTEGER; + } + break; + + case PM_EFLOAT: + case PM_FFLOAT: + if (v.type != MN_FLOAT) { + v.u.d = (double)v.u.l; + v.type = MN_FLOAT; + } + break; + } + } return v; } diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst index 8da17f7f4..8e0730d8d 100644 --- a/Test/C01arith.ztst +++ b/Test/C01arith.ztst @@ -16,7 +16,7 @@ print -- $(( rnd = there * 10000 )) # save rounding problems by converting to integer 0:basic floating point arithmetic ->31415. +>31415 integer rnd (( rnd = ((29.1 % 13.0 * 10) + 0.5) )) @@ -300,3 +300,11 @@ print $(( 0b2 )) 1:Binary numbers don't tend to have 2's in ?(eval):1: bad math expression: operator expected at `2 ' + + integer varassi + print $(( varassi = 5.5 / 2.0 )) + print $varassi +0:Integer variable assignment converts result to integer +>2 +>2 +# It's hard to test for integer to float. -- cgit v1.2.3 From 3a99ef322dafcd2cf833b2a0668436ac120df1b3 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 15 Jan 2015 13:52:08 +0000 Subject: 34280: more widespread use of FORCE_FLOAT. Add the case of variables read for use in arithmetic expressions. --- ChangeLog | 4 ++++ Doc/Zsh/options.yo | 7 ++++--- Src/math.c | 13 ++++++++++++- Test/C01arith.ztst | 10 ++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) (limited to 'Src/math.c') diff --git a/ChangeLog b/ChangeLog index ce150381b..1da768569 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2015-01-15 Peter Stephenson + * 34280: Doc/Zsh/options.yo, Src/math.c, Test/C01arith.ztst: + make FORCE_FLOAT option also cover variables when read for + use in arithmetic expressions. + * 34287 (see 34286 from Markus Trippelsdorf): Src/zsh.mdd: use -E argument for generating signal names if gcc is preprocessor. diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index 076aaf44f..8a0222cfd 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -496,9 +496,10 @@ pindex(NOFORCEFLOAT) cindex(floating point, forcing use of) cindex(forcing use of floating point) item(tt(FORCE_FLOAT))( -Constants in arithmetic evaluation will be treated as floating point -even without the use of a decimal point. Integers in any base -will be converted. +Constants in arithmetic evaluation will be treated as +floating point even without the use of a decimal point; the +values of integer variables will be converted to floating point when +used in arithmetic expressions. Integers in any base will be converted. ) pindex(GLOB) pindex(NO_GLOB) diff --git a/Src/math.c b/Src/math.c index db42d0f7c..c047725c5 100644 --- a/Src/math.c +++ b/Src/math.c @@ -336,16 +336,27 @@ enum prec_type { static mnumber getmathparam(struct mathvalue *mptr) { + mnumber result; if (!mptr->pval) { char *s = mptr->lval; mptr->pval = (Value)zhalloc(sizeof(struct value)); if (!getvalue(mptr->pval, &s, 1)) { mptr->pval = NULL; + if (isset(FORCEFLOAT)) { + result.type = MN_FLOAT; + result.u.d = 0.0; + return result; + } return zero_mnumber; } } - return getnumvalue(mptr->pval); + result = getnumvalue(mptr->pval); + if (isset(FORCEFLOAT) && result.type == MN_INTEGER) { + result.type = MN_FLOAT; + result.u.d = (double)result.u.l; + } + return result; } static mnumber diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst index 8e0730d8d..ea87af257 100644 --- a/Test/C01arith.ztst +++ b/Test/C01arith.ztst @@ -308,3 +308,13 @@ >2 >2 # It's hard to test for integer to float. + + integer ff1=3 ff2=4 + print $(( ff1/ff2 )) + setopt force_float + print $(( ff1/ff2 )) + unsetopt force_float +0:Variables are forced to floating point where necessary +# 0.75 is exactly representable, don't expect rounding error. +>0 +>0.75 -- cgit v1.2.3 From 2ef4b38461dfb554ed2226d9de8958703bc00b98 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 15 Apr 2015 10:20:06 +0100 Subject: 34892 (slightly tweaked): math evaluation fix An empty expression resulting from substitution includes a Nularg, which needs handling the same as an empty string. --- ChangeLog | 3 +++ Src/math.c | 4 ++-- Test/C01arith.ztst | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'Src/math.c') diff --git a/ChangeLog b/ChangeLog index a5d8d7e85..e2d561105 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-04-15 Peter Stephenson + * 34892 (slightly tweaked): Src/math.c, Test/C01arith.ztst: fix + math evaluation with empty expression resulting from substitution. + * 34887: Src/exec, Test/E01options.ztst: assignments before "command special-builtin/func" in POSIX_BUILTINS mode behave as normal command. Tidy up case handling in code and add test. diff --git a/Src/math.c b/Src/math.c index c047725c5..2105180c8 100644 --- a/Src/math.c +++ b/Src/math.c @@ -1398,7 +1398,7 @@ matheval(char *s) if (!mlevel) outputradix = outputunderscore = 0; - if (!*s) { + if (!*s || *s == Nularg) { x.type = MN_INTEGER; x.u.l = 0; return x; @@ -1435,7 +1435,7 @@ mathevalarg(char *s, char **ss) * * To avoid a more opaque error further in, bail out here. */ - if (!*s) { + if (!*s || *s == Nularg) { zerr("bad math expression: empty string"); return (zlong)0; } diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst index d3176dd5e..e2dfe56fc 100644 --- a/Test/C01arith.ztst +++ b/Test/C01arith.ztst @@ -383,4 +383,7 @@ print ${$(( $1 * 100 ))%%.[0-9]#}) 0:Arithmetic substitution nested in parameter substitution >3246 - + + print $((`:`)) +0:Null string in arithmetic evaluation after command substitution +>0 -- cgit v1.2.3 From 493fe2b4440679ca73d9022d94129039b9eacfeb Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 15 Apr 2015 18:14:27 +0100 Subject: unposted: rewrite Nularg math handling to be like other cases --- ChangeLog | 3 +++ Src/math.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'Src/math.c') diff --git a/ChangeLog b/ChangeLog index e2d561105..0d4521453 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-04-15 Peter Stephenson + * unposted: Src/math.c: rewrite last commit to look more + like other uses of Nularg. + * 34892 (slightly tweaked): Src/math.c, Test/C01arith.ztst: fix math evaluation with empty expression resulting from substitution. diff --git a/Src/math.c b/Src/math.c index 2105180c8..97a97b32b 100644 --- a/Src/math.c +++ b/Src/math.c @@ -1398,7 +1398,9 @@ matheval(char *s) if (!mlevel) outputradix = outputunderscore = 0; - if (!*s || *s == Nularg) { + if (*s == Nularg) + s++; + if (!*s) { x.type = MN_INTEGER; x.u.l = 0; return x; @@ -1435,7 +1437,9 @@ mathevalarg(char *s, char **ss) * * To avoid a more opaque error further in, bail out here. */ - if (!*s || *s == Nularg) { + if (*s == Nularg) + s++; + if (!*s) { zerr("bad math expression: empty string"); return (zlong)0; } -- cgit v1.2.3