develooper Front page | perl.perl5.porters | Postings from March 2008

Re: left_shift problem

Thread Previous | Thread Next
Reini Urban
March 24, 2008 05:23
Re: left_shift problem
Message ID:
Yitzchak Scott-Thoennes schrieb:
> On Sun, March 23, 2008 5:15 pm, Reini Urban wrote:
>> Yitzchak Scott-Thoennes schrieb:
>>> By design, the numeric bit ops give their arguments UV context (or,
>>> under use integer, IV context).  If another type of numeric arg is
>>> provided, it is converted via a C cast (which doesn't quite match your
>>> terms "upgraded" or "degraded") and produce a UV-range (or, under use
>>> integer, IV-range) result.  Like all context application, it is
>>> something imposed on the operands by the operator.
>> Thanks! This explains it perfectly.
>> But still, the degration detail.
>> Assume UV 2^32-1 and HINT_INTEGER in the op =>
>> IV not representable.
>> left_shift would make it representable again, but the cast in const IV i =
>> TOPi; threw it away before, before shifting.
> I'm not understanding exactly what case you mean, especially the "left_shift
> would make it representable again".  Unless you are thinking of right_shift?
> Can you show the relevant perl code snippet and its actual and your desired
> results?

Of course I meant a right_shift, bringing it back into our range.

Take some number between LONG_MAX and ULONG_MAX.
I have 64bitints, so
$ perl -Dx -e'my $uv=9223372036854775807*2; print $uv," ",($uv>>1)," "; 
{use integer; print $uv, " ",$uv >> 1}'
51                  TYPE = right_shift  ===> 47
                     TARG = 4
                     FLAGS = (SCALAR,KIDS)
49                      TYPE = padsv  ===> 50
                         TARG = 1
                         FLAGS = (SCALAR)
50                      TYPE = const  ===> 51
                         TARG = 8
                         FLAGS = (SCALAR)
18446744073709551614 9223372036854775807 18446744073709551614 -1

use integer => $^H=1, => op_private=1,
so the right_shift took the uv as iv (highest bit as sign),
then shifted it
   SETi(i >> shift);
and lost it.

This can be avoided and actually is avoided in all lisp's - because with 
"(the integer ...)" local type declaration, it is upgraded to an 
unsigned, if the signed cannot hold it. Not talking about bignums.

But should it be avoided in perl with use integer?
My common sense would yes, because bit operations as common integer 
arithmetic are usually enforced with use integer, and they should
cleary work as UV.
Or fix the docs of use integer, to tell the truth about downgrading UV's 
to IV's when doing bitops with use integer.

$ perl5.10.0d -MO=Debug,-exec -e'my $uv=(1<<32)-1; print $uv," "; {use
integer; print $uv, " ",$uv >> 1}'

BINOP (0x1469620)
         op_ppaddr       PL_ppaddr[OP_RIGHT_SHIFT]
         op_next         0x14695b0 LISTOP [OP_PRINT]
         op_sibling      0x0
         op_targ         4
         op_type         69
         op_opt          1
         op_flags        6
         op_private      1
         op_first        0x14695e8 OP [OP_PADSV]
         op_last         0x1469600 SVOP [OP_CONST]

without use integer:
$ clisp -q -x '(setq i (* 2 9223372036854775807))(list i (ash i -1))'
(18446744073709551614 9223372036854775807)

and with use integer:
$ clisp -q -x '(setq i (* 2 9223372036854775807))(list i (the integer 
(ash i -1)))'
(18446744073709551614 9223372036854775807)

ash -1 is right shift, ash +1 would be left shift in common lisp.
Reini Urban

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About