Hi Steffen, thanks for that. It will be especially useful for defining (( MAXINT = ~0 >>> 1 )).
This reminds me of some other operations I've been meaning to implement, including true modulus +% (where the sign of the result always matches the divisor) with the corresponding flooring division +/, binary ?: (rather than ternary), non-modulus shifts (so that 1>>32 is 0 on both 32- and 64-bit platforms). It should be noted that non-parameterized functions already exist, though they're awkward to use: f='x*x+y*y' # reusable function $(( x=4, y=3, f )) # 25 $(( x=10, y=2, f )) # 104 The key to parameterized functions is some form of expression-local variables to hold the arguments and other intermediate calculations, and a sane syntax for defining them. More ambitiously, I'd like parameterized numeric functions, bigints, floating point, and overflow trapping. I'm wondering how best to introduce floating point. It seems like there are three feasible approaches: (1) use the existing syntax and operators with automatic detection based on whether the arguments are non-integers. (Although this is what C does, I wouldn't recommend it, because it can result in surprises like 1.5+3/2 → 2.5 where 3/2 is evaluated to 1 before 1+1.5 gets handled as FP. It also means guesswork to pick the appropriate precision for division.) (2) Some sort of marker for the entire expression; for $((…)) it could be useful to allow the expression to be prefaced by a printf format specifier, from which the type of operation can be inferred (including as signed/unsigned, fixing the unsigned right shift btw). Then you get to write $(( %#x 27 )) # 0x1b $(( %.4f 20/3 )) # 6.6667 For the statement form it's still necessary to specify how assignment to a string variable should work, so I would use the same there for consistency. (( %u maxint=~0>>1 )) # correct unsigned operation (3) Extend the existing operators where floating point gives the correct integer result with integer arguments, but define new ones where they differ, especially division // (which is why I wouldn't use // for flooring division). This just leaves open the question of how integer overflow should be handled. Complex numbers and Unicode variable names would be nice too, so that I could write (( y = R*sin(θ) )) or even (( c = ε ** ( a * √-1 * π ) )), but that's much further away. On Sun, 17 Jul 2022, 03:44 Steffen Nurpmeso, <stef...@sdaoden.eu> wrote: > Hello. > > I realized there is no unsigned right shift in bash arithmetic > expression, and thought maybe there is interest. > This is a not even compile-tested diff against 5.1.16. > (Using same tab/space as in surroundings.) > > A nice Sunday i wish everyone. > > diff -Napru bash-5.1.orig/expr.c bash-5.1/expr.c > --- bash-5.1.orig/expr.c 2022-07-16 19:35:21.900221532 +0200 > +++ bash-5.1/expr.c 2022-07-16 19:37:23.243552559 +0200 > @@ -32,7 +32,7 @@ > "**" [(exponentiation)] > "*", "/", "%" > "+", "-" > - "<<", ">>" > + "<<", ">>", ">>>" > "<=", ">=", "<", ">" > "==", "!=" > "&" > @@ -41,7 +41,7 @@ > "&&" > "||" > "expr ? expr : expr" > - "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|=" > + "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", > "&=","^=","|=" > , [comma] > > (Note that most of these operators have special meaning to bash, and an > @@ -112,13 +112,14 @@ > #define LOR 8 /* "||" Logical OR */ > #define LSH 9 /* "<<" Left SHift */ > #define RSH 10 /* ">>" Right SHift */ > -#define OP_ASSIGN 11 /* op= expassign as in Posix.2 */ > -#define COND 12 /* exp1 ? exp2 : exp3 */ > -#define POWER 13 /* exp1**exp2 */ > -#define PREINC 14 /* ++var */ > -#define PREDEC 15 /* --var */ > -#define POSTINC 16 /* var++ */ > -#define POSTDEC 17 /* var-- */ > +#define URSH 11 /* ">>>" Unsigned right SHift */ > +#define OP_ASSIGN 12 /* op= expassign as in Posix.2 */ > +#define COND 13 /* exp1 ? exp2 : exp3 */ > +#define POWER 14 /* exp1**exp2 */ > +#define PREINC 15 /* ++var */ > +#define PREDEC 16 /* --var */ > +#define POSTINC 17 /* var++ */ > +#define POSTDEC 18 /* var-- */ > #define EQ '=' > #define GT '>' > #define LT '<' > @@ -578,6 +579,9 @@ expassign () > case RSH: > lvalue >>= value; > break; > + case URSH: > + lvalue = (uintmax_t)lvalue >> value; > + break; > case BAND: > lvalue &= value; > break; > @@ -837,7 +841,7 @@ expshift () > > val1 = exp3 (); > > - while ((curtok == LSH) || (curtok == RSH)) > + while ((curtok == LSH) || (curtok == RSH) || (curtok == URSH)) > { > int op = curtok; > > @@ -846,8 +850,10 @@ expshift () > > if (op == LSH) > val1 = val1 << val2; > - else > + else if (op == RSH) > val1 = val1 >> val2; > + else > + val1 = (uintmax_t)val1 >> val2; > lasttok = NUM; > } > > @@ -1251,6 +1257,7 @@ _is_multiop (c) > case LOR: > case LSH: > case RSH: > + case URSH: > case OP_ASSIGN: > case COND: > case POWER: > @@ -1424,7 +1431,19 @@ readtok () > } > else if ((c == GT) && (c1 == GT)) > { > - if (*cp == '=') > + if (*cp == GT) > + { > + cp++; > + if (*cp == '=') > + { > + assigntok = URSH; /* a >>>= b */ > + c = OP_ASSIGN; > + cp++; > + } > + else > + c = URSH; > + } > + else if (*cp == '=') > { > assigntok = RSH; /* a >>= b */ > c = OP_ASSIGN; > > --steffen > | > |Der Kragenbaer, The moon bear, > |der holt sich munter he cheerfully and one by one > |einen nach dem anderen runter wa.ks himself off > |(By Robert Gernhardt) > >