bug-bash
[Top][All Lists]

## Re: Arithmetic expression: interest in unsigned right shift?

 From: Martin D Kealey Subject: Re: Arithmetic expression: interest in unsigned right shift? Date: Sun, 17 Jul 2022 14:05:35 +1000

```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, <steffen@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)
>
>

```

reply via email to