Perl Weekly Challenge 121: Invert Bit

by Abigail

Challenge

You are given integers 0 <= $m <= 255 and 1 <= $n <= 8.

Write a script to invert $n bit from the end of the binary representation of $m and print the decimal representation of the new binary number.

Example

Input: $m = 12, $n = 3
Output: 8

Binary representation of $m = 00001100
Invert 3rd bit from the end = 00001000
Decimal equivalent of 00001000 = 8

Input $m = 18, $n = 4
Output: 26

Binary representation of $m = 00010010
Invert 4th bit from the end = 00011010
Decimal equivalent of 00011010 = 26

Solution

Third week in a row where we have to manipulate bits! See Swap Nibbles and Swap Odd/Even Bits.

If we take a number, and look at its binary representation, we have:

\[ \ldots b_{n+1} b_{n} b_{n-1} \ldots b_3 b_2 b_1 \]

Inverting bit \(n\), we get:

\[ \ldots b_{n+1} \overline{b_{n}} b_{n-1} \ldots b_3 b_2 b_1 \]

We can do this by some bit fiddling. Recall the truth table for the exclusive or operation:

\[ \begin{array}{|c|c|c|} \hline a & b & a \oplus b \\ \hline 0 & 0 & 0 \\ 1 & 0 & 1 \\ 0 & 1 & 1 \\ 1 & 1 & 0 \\ \hline \end{array} \]

So, we can achieve the given task by taking the bitwise exclusive-or of the original number, and \(1\) shifted \(n - 1\) places the the left:

\[ \begin{array}{|cccccccc|c|} \hline \ldots & b_{n+1} & b_{n} & b_{n-1} & \ldots & b_3 & b_2 & b_1 & M \\ \ldots & 0 & 1 & 0 & \ldots & 0 & 0 & 0 & 1 << (N - 1) \\ \hline \ldots & b_{n+1} & \overline{b_{n}} & b_{n-1} & \ldots & b_3 & b_2 & b_1 & M \oplus (1 << (N - 1)) \\ \hline \end{array} \]

For all solutions, we assuming the input consists of lines with two numbers, $m, and $n on each line. For each input line, we output a single number.

Perl

With the command line options -pla:

$_=$F[0]^1<<--$F[1]

The -p option reads the input line by line, executing the program for each line, and printing whatever is left in $_.

The -a autosplits each input line on white space, putting the results in the array @F. So, for our program, it means that $m is available in $F [0], and $n in $F [1].

Hence, this simply calculates the wanted number.

Find the full program on GitHub.

Languages with bitwise operations

The implementations in languages with bitwise operations, and all look similar. We'll just give the code fragments doing the calculations:

GNU AWK

AWK doesn't have bitwise operations, but GNU AWK does:

print xor ($1, lshift (1, $2 - 1))

Find the full program on GitHub.

C

printf ("%d\n", m ^ (1 << -- n));

Find the full program on GitHub.

Go

fmt . Printf ("%d\n", m ^ (1 << (n - 1)))

Find the full program on GitHub.

Java

System . out . println (m ^ (1 << (n - 1)));

Find the full program on GitHub.

Node.js

console . log (m ^ (1 << -- n))

Find the full program on GitHub.

Free Pascal

writeln (m xor (1 shl (n - 1)));

Find the full program on GitHub.

Python

print (m ^ (1 << (n - 1)))

Find the full program on GitHub.

R

cat (bitwXor (m, (bitwShiftL (1, n - 1))), "\n")

Find the full program on GitHub.

Ruby

puts (m ^ (1 << (n - 1)))

Find the full program on GitHub.

Scheme

(format #t "~d\n" (logxor m (ash 1 (- n 1))))

Find the full program on GitHub.

Tcl

puts [expr $m ^ (1 << ($n - 1))]

Find the full program on GitHub.

Languages without bitwise operations

Without bitwise operations, we have to use arithmetic. First, we find out whether the bit is on by dividing (using integer division) the number \(M\) by \(2^{N-1}\) and checking whether the result is odd or even. If it's even, we add \(2^{N-1}\) to \(M\), else we subtract \(2^{N-1}\) from \(M\).

Bash

((n = 2 ** (n - 1)))
if  (((m / n) % 2))
then ((m = m  - n))
else ((m = m  + n))
fi
echo $m

Find the full program on GitHub.

bc

p = 2 ^ (n - 1)
b = (m / p) % 2
if (b == 1) {
    m = m - p
}
if (b == 0) {
    m = m + p
}
m

Find the full program on GitHub.

Lua

x = 1
for i = 1, n - 1 do
    x = x * 2
end
if  math . floor (m / x) % 2 == 1 then
    m = m - x
else
    m = m + x
end
print (m)

Find the full program on GitHub.

Befunge-93

>>> & :1+!#@_ :& 1- 1 >> \ :! #v_ 1- \ 2* v
^                     ^        $          v
^                     ^<<<<<<<   <<<<<<<<<<
^         v - <                v
^< ,+55 . <   | %2 \g11 / p11: <
          ^ + <

Find the full program on GitHub.


Please leave any comments as a GitHub issue.