in reply to Bitwise operators

Ok, I give up. I've spent a large chunk of the day on this and it's just not happening. I don't understand how to get either a 1 or 0 from combining $value & 1, $value & 2, $value & 4 et al. Using the number 51 as my input each time, I get these values - $value & 1 gives 1, $value & 2 gives 2, $value & 4 gives 2, $value & 8 gives 0, $value & 16 gives 16, $value & 32 gives 32, $value & 64 gives 0, $value & 128 gives 0. It's not making sense to me...

Replies are listed 'Best First'.
Re^2: Bitwise operators
by liverpole (Monsignor) on Dec 25, 2006 at 19:03 UTC
    Would the following help you?  It's my attempt to provide a pictorial representation of what's happening:
    use strict; use warnings; my $value = 51; # Accumulate binary digits ("bits") my @bits = ( ); foreach my $place (0 .. 7) { my $nextbit = mask_off_bit($value, $place); push @bits, $nextbit; } # Display each bit printf "\nNumber %3d in binary is: ", $value; map { print "$_" } reverse @bits; print "\n"; # Test the results against good ol' printf printf " Which is the same as: %08b\n", $value; sub mask_off_bit { my ($num, $place) = @_; my $mask = 1 << $place; # Same as 2 ** $place my $mstr = " " x (8 - $place) . "^"; # Graphic representati +on printf " Num %3d: 0b%08b\n", $num, $num; # Number in decimal & +binary my $bit = ($mask == ($num & $mask))? 1: 0; # Next bit is one or z +ero printf "Mask %3d: %s => bit %d\n", $mask, $mstr, $bit; return $bit; }

    The above code is masking off each bit, using a mask of 1, 2, 4, 8, etc. in the line:

    my $bit = ($mask == ($num & $mask))? 1: 0


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
      Thanks so much for taking the time to do that, but it's a bit advanced for me - there's a lot there I haven't covered and don't recognise : )
Re^2: Bitwise operators
by ysth (Canon) on Dec 25, 2006 at 19:31 UTC
    $value & 1 will always produce 0 or 1 as the result, depending on whether the lowest bit of $value was set. $value & 2 will always produce 0 or 2 as the result, depending on whether the second lowest bit of $value was set. And so on.

    So, you can say:

    if ($value & 128) { print "1"; } else { print "0"; }
      Thanks, that has worked a treat but to produce the full 00110011 representation of 51 I've done this-
      use warnings; use strict; print "Please input a decimal no. to convert to binary : "; chomp (my $value = <STDIN>); if ($value & 1) { print "1"; } else { print "0"; } if ($value & 2) { print "1"; } else { print "0"; } if ($value & 4) { print "1"; } else { print "0"; } if ($value & 8) { print "1"; } else { print "0"; } if ($value & 16) { print "1"; } else { print "0"; } if ($value & 32) { print "1"; } else { print "0"; } if ($value & 64) { print "1"; } else { print "0"; } if ($value & 128) { print "1"; } else { print "0"; }
      I guess there's a much shorter way? Cheers
        There's (almost) always a shorter way ;-)

        First, you're doing the if (...) { ... } else { ... } thing a total of 8 times, so you can reduce that portion of your program by a factor of 8 if you do something like this:
        use warnings; use strict; print "Please input a decimal no. to convert to binary : "; chomp (my $value = <STDIN>); apply_mask($value, 128); apply_mask($value, 64); apply_mask($value, 32); apply_mask($value, 16); apply_mask($value, 8); apply_mask($value, 4); apply_mask($value, 2); apply_mask($value, 1); sub apply_mask { my $value = shift; my $mask = shift; if ($value & $mask) { print "1"; } else { print "0"; } }

        But since the numbers 1 ... 128 are easily computable as powers of two, you could simplify it to:

        use warnings; use strict; print "Please input a decimal no. to convert to binary : "; chomp (my $value = <STDIN>); foreach my $power (0..7) { # Originally 2 ** $power, but that's backwards! my $mask = 2 ** (7 - $power); apply_mask($value, $mask); } sub apply_mask { my $value = shift; my $mask = shift; if ($value & $mask) { print "1"; } else { print "0"; } }

        By the way, just to show you that TMTOWTDI (= "There's more than one way to do it!" = the Perl motto), here's a lookup table solution which trades memory for speed (ie. uses a lot of memory, but is relatively fast):

        use strict; use warnings; my @binary_table = qw( 0 1 10 11 100 101 110 1 +11 1000 1001 1010 1011 1100 1101 1110 11 +11 10000 10001 10010 10011 10100 10101 10110 101 +11 11000 11001 11010 11011 11100 11101 11110 111 +11 100000 100001 100010 100011 100100 100101 100110 1001 +11 101000 101001 101010 101011 101100 101101 101110 1011 +11 110000 110001 110010 110011 110100 110101 110110 1101 +11 111000 111001 111010 111011 111100 111101 111110 1111 +11 1000000 1000001 1000010 1000011 1000100 1000101 1000110 10001 +11 1001000 1001001 1001010 1001011 1001100 1001101 1001110 10011 +11 1010000 1010001 1010010 1010011 1010100 1010101 1010110 10101 +11 1011000 1011001 1011010 1011011 1011100 1011101 1011110 10111 +11 1100000 1100001 1100010 1100011 1100100 1100101 1100110 11001 +11 1101000 1101001 1101010 1101011 1101100 1101101 1101110 11011 +11 1110000 1110001 1110010 1110011 1110100 1110101 1110110 11101 +11 1111000 1111001 1111010 1111011 1111100 1111101 1111110 11111 +11 10000000 10000001 10000010 10000011 10000100 10000101 10000110 100001 +11 10001000 10001001 10001010 10001011 10001100 10001101 10001110 100011 +11 10010000 10010001 10010010 10010011 10010100 10010101 10010110 100101 +11 10011000 10011001 10011010 10011011 10011100 10011101 10011110 100111 +11 10100000 10100001 10100010 10100011 10100100 10100101 10100110 101001 +11 10101000 10101001 10101010 10101011 10101100 10101101 10101110 101011 +11 10110000 10110001 10110010 10110011 10110100 10110101 10110110 101101 +11 10111000 10111001 10111010 10111011 10111100 10111101 10111110 101111 +11 11000000 11000001 11000010 11000011 11000100 11000101 11000110 110001 +11 11001000 11001001 11001010 11001011 11001100 11001101 11001110 110011 +11 11010000 11010001 11010010 11010011 11010100 11010101 11010110 110101 +11 11011000 11011001 11011010 11011011 11011100 11011101 11011110 110111 +11 11100000 11100001 11100010 11100011 11100100 11100101 11100110 111001 +11 11101000 11101001 11101010 11101011 11101100 11101101 11101110 111011 +11 11110000 11110001 11110010 11110011 11110100 11110101 11110110 111101 +11 11111000 11111001 11111010 11111011 11111100 11111101 11111110 111111 +11 ); print "Please input a decimal no. to convert to binary : "; chomp (my $value = <STDIN>); my $binary = $binary_table[$value]; if (!defined($binary)) { die "Sorry, value $value isn't in the table!\n"; } print "Decimal $value = Binary $binary\n";

        It only works for values from 0 to 255, though.

        Update:  Oh, yes ... if you want shorter code instead of faster execution, here's a fancier way of writing it fairly succinctly:

        use warnings; use strict; print "Please input a decimal no. to convert to binary : "; chomp (my $value = <STDIN>); print map { ($value & (1 << (7 - $_)))? 1: 0 } ( 0 .. 7 ); print "\n";

        Update 2:  Reversed the effective order the bits are printed in to make it msb first and lsb last (thanks for pointing that out ysth++).


        s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
        I'm guessing you had them in the other order (128 down to 1).

        Have you covered loops at all? What book is this you are using?