Change a specified bit to 0

Viewed 242

I have a number:

11100111

I want an operation to change a specific bit of my choice to 0.

So, if I wanted it to be :

10100111

for the 7th bit what operation would I use, for, say:

$x = 6;
$y = "11100111";

It's going to look something like:

$z = $y & $x

But, I know that's wrong. I know I could subtract 2^$x from the value, but that seems inelegant.

4 Answers

I think that your use of a string is the wrong way to go. We should use integers instead. We can write the number as an integer this way:

0b11100111

We can create a number, that only has the 7th bit set, this way:

1 << 6

And we can create a number, that has all the bits set, except the 7th:

~(1 << 6)

With that in mind, we can set the 7th bit to zero:

my $x = 6;
my $y = 0b11100111;
my $z = $y & ~(1 << $x);
print "$z\n"

This outputs the decimal 167 which is 10100111 in binary. If we want to output the binary representation of the number, we can do it using printf:

printf "%b\n", $z;

This outputs 10100111.

Since your binary number is really a string, you can use substr to simply replace a 1 with a 0:

use warnings;
use strict;

my $x = 6;
my $y = '11100111';
print "$y\n";
substr($y, (7 - $x), 1) = '0';
print "$y\n";

Prints:

11100111
10100111

My Bit::Manip distribution does this kind of thing.

use strict;
use warnings;

use Bit::Manip qw(:all);

my $num = 0b11100111;
my $bit_position = 6;

my $flipped = bit_off($num, $bit_position);

printf("orig:    %b\n", $num);
printf("flipped: %b\n", $flipped);

Output:

orig:    11100111
flipped: 10100111

See the documentation for everything bitwise the library can do.

You could also use vec to manipulate the bits:

my $v = pack "B8", "11100111"; # Convert one-byte bitstring into a vector
printf "%vb\n", $v;
vec($v, 6, 1) = 0; # Set the sixth bit
printf "%vb\n", $v;
my $s = unpack "B8", $v; # Back to a string of 1's and 0's
# prints:
# 11100111
# 10100111
Related