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

I wanted to generate a sequence of binary numbers so I tried code like:

print unpack ('B16', $_)."\n" for (0..10);

which generated:

00110000 00110001 00110010 00110011 00110100 00110101 00110110 00110111 00111000 00111001 0011000100110000

which is not what I expected! Where I expected that the for loop variable would be stored as a number, it seems to be being stored as a numeric string: '0'..'10'. Why is that? Is it possible to coerce Perl into storing a number as an integer in that sort of context?

Note that I have solved my initial problem using an sprintf, which may well be what I should have used in the first place.


Perl is Huffman encoded by design.

Replies are listed 'Best First'.
Re: unpack in incrementing variables
by davido (Cardinal) on Oct 14, 2005 at 02:32 UTC

    It seems like you want something like this:

    for ( 0 .. 32768 ) { print unpack( "B16", pack( "n", $_ ) ), "\n"; }

    Of course that produces a LOT of output, but it will produce bitstrings in contiguous order, most significant digit at the 'left', and least significant at the 'right'.

    One problem that it seemed like you were running into was the difference between ascending and descending bit order, combined with the difference between big-endian and little-endian packed integers.

    There's some documentation on all this in pack, but a more thorough discussion in perlpacktut.

    As for the question of why the iteration values in your foreach loop are being stringified, that can be explained in the documentation for unpack:

    unpack does the reverse of pack: it takes a string and expands it out into a list of values. (In scalar context, it returns merely the first value produced.)

    The key is that it treats its second arg as a string.


    Dave

Re: unpack in incrementing variables
by demerphq (Chancellor) on Oct 14, 2005 at 07:54 UTC

    As you said, use (s)printf. (printf doesnt respect -l so this looks a touch more clumsy than it needs to).

    D:\dev>perl -e "printf '%08b%s',$_,$/ for 1..10" 00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000 00001001 00001010

    Unpack operates on strings not on integers so you need to ensure that chr(10) is passed in and not '10'.

    D:\dev>perl -le "print unpack 'B*',chr($_) for 1..10" 00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000 00001001 00001010
    ---
    $world=~s/war/peace/g

      Thank you. At last the answer to the question I actually asked. The question was why, not how. The answer is "Unpack operates on strings not on integers".


      Perl is Huffman encoded by design.

        I think people were inclined to show the how because the why is in the docs:

        unpack TEMPLATE,EXPR
        "unpack" does the reverse of "pack": it takes a string and expands it out into a list of values. (In scalar context, it returns merely the first value produced.)

        But I did it because i hadnt had my coffee before I posted (was waiting for it finish being made) and didnt read the question properly. Luckily the coffee was finished just after I hit submit so I realized the error and fixed it right after. :-)

        ---
        $world=~s/war/peace/g

        The question was why, not how.
        The question "Is it possible to...?" includes an implicit "How?" Answering such question with a simple "yes" is generally seen as teasing.

        Caution: Contents may have been coded under pressure.
Re: unpack in incrementing variables
by ikegami (Patriarch) on Oct 14, 2005 at 01:58 UTC
    print unpack ('B16', pack('I', $_))."\n" for (0..10);

      Close, but no banana.

      print unpack ('B16', pack('I', $_))."\n" for (250..260); 1111101000000000 1111101100000000 1111110000000000 1111110100000000 1111111000000000 1111111100000000 0000000000000001 0000000100000001 0000001000000001 0000001100000001 0000010000000001

      which is not what I would like either.

      Besides, the question was why, not how. I have a how.


      Perl is Huffman encoded by design.

        Counter intuitively (for me at least):

        print unpack ('B16', pack('n', $_))."\n" for (250..260); 0000000011111010 0000000011111011 0000000011111100 0000000011111101 0000000011111110 0000000011111111 0000000100000000 0000000100000001 0000000100000010 0000000100000011 0000000100000100

        the "network" format (big endian) does what I want on a little endian (Windows) system.


        Perl is Huffman encoded by design.
Re: unpack in incrementing variables
by pg (Canon) on Oct 14, 2005 at 02:00 UTC

    00110000 is 48, and that's the ASCII code for '0'. That's the explanation for your first line, the rest are the same, and the last line represents two characters: '1' and '0'. So that's expected with the code you have.

Re: unpack in incrementing variables
by EvanCarroll (Chaplain) on Oct 14, 2005 at 02:18 UTC
    Might better suit you:
    perl -e'printf("%08b\nb", $_) for (0..10);'
    There is also a sprintf, though it probably a little slower than unpack.


    Evan Carroll
    www.EvanCarroll.com