On Mon, 16 Jul 2001 16:09:33 +1000, Rodney Van Cooten wrote:

>I'm going mad! I'm trying to use some smallish integers as bit vectors.
>
>Can anyone tell me why the following produces different (erroneous) 
>results under MacPerl to those on other Unix perls I have access to?
>
>use integer;
>$a = 0x2a | 0; # 42 = 2 + 8 + 32; 106 = 2 + 8 + 32 + 64
>
>print "$a\n";
>
>$a1 = 0x01; $count = 0;
>
>while (($a > 0) && ($count < 20)) {
>     print (($a & $a1));
>     print  ", $a, $a1, $count\n";
>     if (($a1 & $a)>0) {
>         print "We have a $a1\n";
>         $a -= $a1;
>     }
>     $a1 <<= 1;
>     $count++;
>}
>print "We went through $count times\n";
>
>produces in MacPerl 5.2.0r4 on an iMac running system 9.1:
>
>42
>0, 42, 1, 0
>2, 42, 2, 1
>We have a 2
>0, 40, 4, 2
>We have a 4
>0, 36, 8, 3
>0, 36, 16, 4
>32, 36, 32, 5
>We have a 32
>0, 4, 64, 6
>We have a 64
>We went through 7 times

Let me venture a guess.

Bitwise operators are the only operators in Perl that act differently on
"text" than on "numbers", both actually scalars. My guess is that the
print statements, where you use the scalars as text, change the nature
of the scalar to text, if it's the first time it's been used as text
since the value changed.

Note that a perl scalar internally keeps a version of the value in
numerical representation, if it's ever used as a number, and of the text
representation, if it's ever used as text. If a representation is needed
and not present, perl will convert from one to the other and store it.

I think that on MacPerl, this changes the "nature" of the scalar.

Note that this works on MacPerl too:

     if ((($a+0) & $a)>0) {
         print "We have a $a1\n";
         ...
     }

The addition (with zero) makes sure the LHS is a number.


BTW when working with bit flags on Perl, be sure to check out vec().
This rather awkward (IMO) keyword can treat a scalar (as string) as a
one-dimensional array of small integers. You decide how small (3rd
parameter). Bitwise and ("&") etc. can be used on the scalars, which
then will be treated as strings. Here's a modified version ($a is the
number, $s is the "bitflags" string version):

    $a = 0x2a | 0; # 42 = 2 + 8 + 32; 106 = 2 + 8 + 32 + 64

    $s = pack 'V', $a;
    print "$a\n";

    $a1 = 0x01; $count = 0;

    while (($a1 < $a) && $count < 20) {
         if (vec($s, $count, 1)) {
             print "We have a $a1\n";
         }
         $a1 <<= 1;
         $count++;
    }
    print "We went through $count times\n";

-->

        42
        We have a 2
        We have a 8
        We have a 32
        We went through 6 times

vec() is not limited to 32 or 64 bits, or whatever the number of bits
for an integer on your platform may be.

BTW just as with substr(), you can use vec() as an L-value, i.e. you can
assign to it.

-- 
        Bart.

Reply via email to