thevoid has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, hoping you won't mind helping me out with another beginners query... have been at it for hours and can't make it work. Have been asked to write a program which asks for a decimal number to convert to a binary one. The textbook hints that I "might want to use the bitwise and operator, 8 times". Whilst I have covered the & operator and thought I understood it, this is the first time I've had to use it and guess I'm not really getting it. Have started with the customary
#!/usr/bin/perl #converter.plx use warnings; use strict; print "Please input a decimal no. to convert to binary : "; chomp (my $value = <STDIN>); print "$value .....
Just not sure where to go after that, Many thanks

Replies are listed 'Best First'.
Re: Bitwise operators
by jettero (Monsignor) on Dec 24, 2006 at 13:14 UTC

    When you're in the mood to check for correctness, have a look at pack. You can solve this problem in perl with pack("f", 3.14159). Though, I suspect you want the long answer so you can learn how pack does it's magic. I have learned that you won't learn anything unless you do it yourself, but if you do a google search, you're likely to turn up c-code for BCD.

    -Paul

Re: Bitwise operators
by mvaline (Friar) on Dec 24, 2006 at 13:57 UTC
    You appear to be working through a list of basic programming questions in Perl for the first time. I recommend you spend some time reading through the perlfaq documents, which are designed to cover this type of question. For example, this question is covered in perlfaq4 under "How do I convert between numeric representations/bases/radixes."

    If you read through the documentation and are still stuck, then ask a more targeted question here and we will be happy to help you.

Re: Bitwise operators
by davido (Cardinal) on Dec 24, 2006 at 22:08 UTC

    Your original question deals with bitwise operators as a method of examining the bits behind a number. ...then we started talking about unpack() instead, which works, but may not satisfy the requirements of what you're trying to learn.

    I implemented a solution just now using the & operator (which is a bit-wise operator), with $number & $bit_value, iterating over the values of individual bits. I don't want to ruin your homework learning experience, so I guess I'll just try to describe the method:

    Start by setting $bit_value to 1. This represents the value of the least significant bit. Then take $number & $bit_value. If you get a non-zero value, that bit is 'set'. Keep track of it. Then repeat the process for $bit_value being equal to 2, then to 4, then to 8, 16, 32, and so on. Each time keep track of whether the specific bit is set.

    This will give you a list of set or unset bits, in order of least significant to most significant. Once you've worked through it yourself with those hints, try posting some code, and I'll show you a comparison with how I did it.


    Dave

      Great, thanks Dave - will have a go tomorrow : )

        Ok, I've seen what you posted lower down in this thread, and wanted to follow up to my earlier promise to offer some code.

        The following solution will work for any integer, whether it requires 4 bits or 32 to represent it.

        use strict; use warnings; my $number = 75; my $bitval = 1; my $bits = ''; while ( $bitval <= $number ) { my $bit = $number & $bitval ? 1 : 0; $bits = $bit . $bits; $bitval *= 2; } print $bits, "\n";

        $bitval contains the mask value, and is incremente by times two after each iteration. That makes the masks 1, 2, 4, 8, 16, 32.... etc. (look familiar?). The ... ? ... : ... (ternary operator) serves to turn a bit value into just a zero or one. The rest I think you'll figure out as you look at it.


        Dave

Re: Bitwise operators
by liverpole (Monsignor) on Dec 24, 2006 at 13:56 UTC
    Hi thevoid,

    No need to mask off individual bits (though you can do that if you really need to using & and >> -- see perlop for more on these operators).

    Try reading the documentation for sprintf (and search for the word binary).  You should find that it has all the power you need!

    Update:  You may prefer the nearly identical printf for your purposes.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: Bitwise operators
by thevoid (Scribe) on Dec 24, 2006 at 14:20 UTC
    Heh, beat me to it... just came back to say that I've just discovered the perlfaq and in perlfaq4 found the answer to my troubles using unpack
    #!/usr/bin/perl #converter.plx use warnings; use strict; print "Please input a decimal no. to convert to binary : "; chomp (my $value = <STDIN>); $value = unpack("B*", pack("N", $value)); print "$value";
    Thanks for everyone's help and patience, hopefully the perlfaq will provide some answers from hereon in, though it's nice to know there is somewhere to come and ask very basic questions without setting off howls of derisive laughter!

      While you're diving into Perl's documentation, don't forget about the pack() tutorial: perlpacktut, as well as the individual docs for pack and unpack. Whenever I use pack and unpack I find myself referring back to pack's documentation. And perlpacktut is extremely helpful when you're starting out with this stuff.


      Dave

        nice, will do
Re: Bitwise operators
by ysth (Canon) on Dec 24, 2006 at 19:50 UTC
    I'm not sure whether you are looking to solve this problem in any way, or solve it in the particular way they suggest. If the former, sprintf is probably the easiest way; if the latter, you can find out the value of individual bits of $value with $value & 1, $value & 2, $value & 4, $value & 8, etc., and form a string of "0"s and "1"s based on those.
      Yeah, that looks like the the way they meant. The tutorial I'm doing is good in some ways, but occasionally there seems to be too large a gap between what has been demonstrated and what I'm asked to do. So if I can't do it the exact way that was intended I'm happy to find another solution, I'm sure I'll come across all the different ways of going about things anyway the further I get in to Perl.
        I'm sure I'll come across all the different ways of going about things anyway the further I get in to Perl.
        Actually, probably not. Perl has lots of nooks and crannies that most people never need to venture into. But that's OK. From the Programming Perl 3rd ed. preface:
        Most important, you don't have to know everything there is to know about Perl before you can write useful programs. You can learn Perl "small end first". You can program in Perl Baby-Talk, and we promise not to laugh. Or more precisely, we promise not to laugh any more than we'd giggle at a child's creative way of putting things. Many of the ideas in Perl are borrowed from natural language, and one of the best ideas is that it's okay to use a subset of the language as long as you get your point across. Any level of language proficiency is acceptable in Perl culture. We won't send the language police after you. A Perl script is "correct" if it gets the job done before your boss fires you.
Re: Bitwise operators
by thevoid (Scribe) on Dec 25, 2006 at 09:50 UTC
    Ok here's what I've done, which works -
    #!/usr/bin/perl #converter.plx use warnings; use strict; print "Please input a decimal no. to convert to binary : "; chomp (my $value = <STDIN>); print "$value & 1", "$Value & 2", "$value & 4"; print "$value & 8", "$value & 16", "$value & 32"; print "$value & 64", "$value & 128\n";
    but I've started the next chapter which is on arrays and hashes, so although I'm not sure how to do it yet, I'm thinking there's a probably a shorter way? Paul.
      Hi again, thevoid,

      I just now read this earlier post of yours.

          print "$value & 1", "$Value & 2", "$value & 4";

      The problem you're having is that you can only interpolate a certain amount within strings, and doing bit-wise arithmetic is a little too much.

      You could do this if you used printf like so:
      printf "%d, %d, %d, ", $value & 1, $value & 2, $value & 4;

      And you could even convert to one or zero values by applying the appropriate shifts:

      printf "%d, %d, %d, ", ($value & 1), ($value & 2) >> 1, ($value & 4) > +> 2;

      s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
        Hi, just spotted this!

        That's pretty nifty also : )

Re: Bitwise operators
by thevoid (Scribe) on Dec 25, 2006 at 18:09 UTC
    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...
      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 : )
      $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
Re: Bitwise operators
by thevoid (Scribe) on Dec 24, 2006 at 13:25 UTC
    excellent, thanks ; )
Re: Bitwise operators
by thevoid (Scribe) on Dec 25, 2006 at 21:46 UTC
    @ liverpole, thanks loads for that - makes a lot of sense.

    @ysth, Yeah, should have been the other way round. I am trying to work through this

    http://www.perl.org/books/beginning-perl/

    and this excercise is at the end of chapter 2, so am not up to loops yet.

Re: Bitwise operators
by thevoid (Scribe) on Dec 25, 2006 at 12:16 UTC
    hang on, no it doesn't back to the drawing board...