-------- Original Message --------
Date: Tue, 07 Oct 2008 11:55:51 +0100
From: Pádraig Brady <[EMAIL PROTECTED]>
To: Chet Ramey <[EMAIL PROTECTED]>
CC: [EMAIL PROTECTED]

I was just discussing bit shifting with Tim Hockin using shell
arithmetic expansion, and he pointed out that bash and ksh
use arithmetic rather than logical shift for the >> operator.

Now arithmetic shift is not useful on 2's compliment machines,
and moreover it's compiler dependent as to whether arithmetic
or logical shift is done for >>. Therefore to increase usefulness
and decrease ambiguity I suggest applying something like the
attached simple patch.

I know the opengroup spec says to use signed ints,
but I think that is intended to disambiguate input and output,
rather than defining internal operations.

Some sample output from the patched version:

  $ printf "%x\n" $((0x8000000000000000>>1))
  4000000000000000

  $ smax=$((-1>>1)); echo $smax
  9223372036854775807

  $ echo $((-0x4000000000000000/2)) $((-0x4000000000000000>>1))
  -2305843009213693952 6917529027641081856

And corresponding output from unpatched bash:

  $ printf "%x\n" $((0x8000000000000000>>1))
  c000000000000000

  $ smax=$((-1>>1)); echo $smax
  -1

  $ echo $((-0x4000000000000000/2)) $((-0x4000000000000000>>1))
  -2305843009213693952 -2305843009213693952

cheers,
Pádraig.

--- expr.arithmetic_shift.c	2008-10-06 07:35:09.000000000 +0000
+++ expr.c	2008-10-06 07:11:44.000000000 +0000
@@ -452,7 +452,7 @@
 	      lvalue <<= value;
 	      break;
 	    case RSH:
-	      lvalue >>= value;
+	      lvalue = ((uintmax_t)lvalue) >> value;
 	      break;
 	    case BAND:
 	      lvalue &= value;
@@ -703,7 +703,7 @@
       if (op == LSH)
 	val1 = val1 << val2;
       else
-	val1 = val1 >> val2;
+	val1 = ((uintmax_t)val1) >> val2;
     }
 
   return (val1);

Reply via email to