Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Making all nibble zero lower than the offset

by spriyada29 (Initiate)
on Nov 20, 2018 at 01:56 UTC ( [id://1226043]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, I am learning perl and having trouble with doing bit manipulation . I want to make all the nibbles 0 lower than the offset and including the current nibble depending on the offset value.

Eg. 1 .if I have a data stream as 0b1111_1111_1111 and Offset is 5 then my output should be 0b1111_0000_0000(making the last and second last nibble 0) 2. if Data= 0b1111_1111_1111 and offset is 3 then my output is 0b1111_1111_0000(making just the last nibble 0)

Can someone please suggest a way to do it.

  • Comment on Making all nibble zero lower than the offset

Replies are listed 'Best First'.
Re: Making all nibble zero lower than the offset
by Cristoforo (Curate) on Nov 20, 2018 at 03:02 UTC
    Hello spriyada29,

    I don't know if this is a possible answer but it works with the example binary string you provided.

    #!/usr/bin/perl use strict; use warnings; my $bin = 0b1111_1111_1111; for my $factor (3,5) { # round up to multiple of 4 my $shift = $factor + (-$factor % 4); my $c = $bin >> $shift; $c <<= $shift; printf "%b\n", $c; }
    Prints out:
    111111110000 111100000000
Re: Making all nibble zero lower than the offset
by stevieb (Canon) on Nov 20, 2018 at 02:09 UTC

    I'm a tiny bit biased here, but Bit::Manip might help :)

    A few bit manipulation questions recently. Must be the start of a new school year or something.

      or a new hack for game consoles or some other devices haha
Re: Making all nibble zero lower than the offset
by johngg (Canon) on Nov 20, 2018 at 12:42 UTC

    I'm assuming that this question is associated with the generation of arrays of nybbles in the Bit manipulation of a bit stream to generate different elements of an array with each nibble taking either 0 or 1 in perl post and that you might want to act on any element of the array, not just those in which all nybbles are 1111. If so, you can create a mask where nybbles to leave untouched are set to 1111 and those to zero are set to 0000 then AND it with the relevant array element. It is not clear from the OP but I'm also assuming that your offset is one-based counting from the right in bits, i.e. offsets 1 through 4 mask the rightmost nybble, 5 through 8 the rightmost two nybbles etc. The code is simple to modify if counting is zero-based.

    use strict; use warnings; use feature qw{ say }; my $sep = sub { say q{-} x 24; }; my $baseStr = q{{0,f}}; my $width = 4; my $globStr = $baseStr x $width; $sep->(); foreach my $offset ( 3, 5, 8, 9 ) { say qq{Offset - $offset}; my @bitStrs = map { pack q{H*}, $_ } glob $globStr; my $div = int( $offset / 4 ); my $rem = $offset % 4; my $nybblesToMask = $div + ( $rem ? 1 : 0 ); my $mask = pack q{H*}, q{f} x ( $width - $nybblesToMask ) . q{0} x $nybblesToMask; say q{Mask - }, unpack qq{B@{ [ $width * 4 ]}}, $mask; say q{Element 5 - }, unpack qq{B@{ [ $width * 4 ]}}, $bitStrs[ +5 ]; say q{E. 5 & mask - }, unpack qq{B@{ [ $width * 4 ]}}, $bitStrs[ 5 ] & $mask; say q{Element 15 - }, unpack qq{B@{ [ $width * 4 ]}}, $bitStrs[ +15 ]; say q{E. 15 & mask - }, unpack qq{B@{ [ $width * 4 ]}}, $bitStrs[ 15 ] & $mask; $sep->(); }

    The output.

    ------------------------ Offset - 3 Mask - 1111111111110000 Element 5 - 0000111100001111 E. 5 & mask - 0000111100000000 Element 15 - 1111111111111111 E. 15 & mask - 1111111111110000 ------------------------ Offset - 5 Mask - 1111111100000000 Element 5 - 0000111100001111 E. 5 & mask - 0000111100000000 Element 15 - 1111111111111111 E. 15 & mask - 1111111100000000 ------------------------ Offset - 8 Mask - 1111111100000000 Element 5 - 0000111100001111 E. 5 & mask - 0000111100000000 Element 15 - 1111111111111111 E. 15 & mask - 1111111100000000 ------------------------ Offset - 9 Mask - 1111000000000000 Element 5 - 0000111100001111 E. 5 & mask - 0000000000000000 Element 15 - 1111111111111111 E. 15 & mask - 1111000000000000 ------------------------

    I hope this is helpful.

    Update: Clarified wording re the offset.

    Cheers,

    JohnGG

Re: Making all nibble zero lower than the offset
by trippledubs (Deacon) on Nov 20, 2018 at 05:19 UTC
    #!/usr/bin/env perl use strict; use warnings; my $data = 0b1111_1111_1111; my $offset = 8; my $nibble_mask = 0xF; while (not 1<<$offset-1 & $nibble_mask) { $data ^= $nibble_mask; $nibble_mask <<= 4; } $data = $data ^ $nibble_mask; printf("%b\n",$data);
      How naive I was to loop through looking for something already given...
      #!/usr/bin/env perl use strict; use warnings; my $data = 0b1111_1111_1111; my $offset = 5; my $mask = hex 'F' x ($offset % 4 == 0 ? $offset / 4 : $offset / 4 + 1 +); printf("%b\n",$data ^ $mask);
Re: Making all nibble zero lower than the offset
by GrandFather (Saint) on Nov 21, 2018 at 00:49 UTC

    There are a few bit manipulation tricks worth knowing about when you are dealing with masking blocks of bits:

    #!/usr/bin/env/perl use strict; use warnings; my $oValue = 0xAAAA; my $setBit = 1 << 5; my $mask = $setBit - 1; my $setBits = $oValue | $mask; my $resetBits = $oValue & ~$mask; printf "orig: %016b\n", $oValue; printf " bit: %016b\n", $setBit; printf "mask: %016b\n", $mask; printf " set: %016b\n", $setBits; printf " clr: %016b\n", $resetBits;

    Prints:

    orig: 1010101010101010 bit: 0000000000100000 mask: 0000000000011111 set: 1010101010111111 clr: 1010101010100000

    Note that ~ generates the 1s complement (inverts each bit) of its operand.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: Making all nibble zero lower than the offset
by ikegami (Patriarch) on Nov 21, 2018 at 05:53 UTC

    If this is to be done repeatedly, I'd go with a lookup table. The table could be built dynamically (e.g. by using the code from the other answers in a loop), but it's probably not worth the effort.

    my @mask_by_offset = ( ( ~0x0000_000F ) x 4, ( ~0x0000_00FF ) x 4, ( ~0x0000_0FFF ) x 4, ( ~0x0000_FFFF ) x 4, ( ~0x000F_FFFF ) x 4, ( ~0x00FF_FFFF ) x 4, ( ~0x0FFF_FFFF ) x 4, ( ~0xFFFF_FFFF ) x 4, ); $val &= $mask_by_offset[$offset];

    The mask are defined in terms of the bits to keep to work with 32-bit ints and 64-bit ints.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1226043]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2024-04-19 15:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found