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

Hi,
Given an unsigned 32 bit value (set initially to zero) and a 32 bit mask.
How would I increment just the masked bits through all their possible combinations, without trying the entire 32 bit range.
e.g. given a mask of 0x0f000007
it'll go through

0x00000000 0x00000001 .. 0x00000007

then

0x01000000 0x01000001 0x01000002 .. 0x01000007 .. 0x02000000 0x02000001 ..

and so on till

0x0F000007

Is there a good and quick way of doing this in perl?

Thanks!

20051110 Janitored by Corion: Removed PRE tags, put in proper formatting

Replies are listed 'Best First'.
Re: Incrementing only the masked bits (sure)
by tye (Sage) on Nov 10, 2005 at 07:30 UTC
    my $mask= 0x0f000007; my $val= $mask; do { printf "0x%08.8x\n", $val; --$val; $val &= $mask; } while( $val != $mask );

    - tye        

      Use:

      printf "0x%08.8x\n", (~$val & $mask);

      to count up.


      Perl is Huffman encoded by design.
      Thanks, I didn't think of decrementing :).

      Definitely does what I need, though it's not what I asked for. hehe.

      p.s. Sorry about the pre thing.

Re: Incrementing only the masked bits
by Roy Johnson (Monsignor) on Nov 10, 2005 at 16:42 UTC
    Here's an incrementing solution, inspired by tye's (but not simply doing the decrement and then subtracting from $mask, which would also work).
    my ($val, $mask) = (-1, 0x01000007); do { $val += ~$mask+1; $val &= $mask; printf "0x%08.8x\n", $val; } while ($val < $mask);

    Caution: Contents may have been coded under pressure.

      My version actually started out in my head closer to:

      my $mask= 0x0f000007; my $val= 0; do { printf "0x%08.8x\n", $val & $mask; $val |= ~$mask; ++$val; } while( $val <= ~0 );

      but in typing it I decided to simplify. (:

      - tye        

Re: Incrementing only the masked bits
by gaal (Parson) on Nov 10, 2005 at 07:27 UTC
    I don't know of an immediate way to do this.

    If you have k bits sets in your mask, the whole iteration has 2**k values. So what you're looking for is a function n_to_masked($mask, $n) that maps a number from 0 .. 2**k-1 to a 32-bit value that fits in your mask. I don't have a really clever way of doing this other than shifting bits left and right, but with $m you know exactly what bits you need to shift how much.

    Update: tye's way is muuuuch more clever. Use that. :-)