Perl Weekly Challenge 119: Swap Nibbles

by Abigail

Challenge

You are given a positive integer $N.

Write a script to swap the two nibbles of the binary representation of the given number and print the decimal number of the new binary representation.

A nibble is a four-bit aggregation, or half an octet.

To keep the task simple, we only allow integer less than or equal to 255.

Examples

Input: $N = 101
Output: 86

Binary representation of decimal 101 is 1100101 or as 2 nibbles (0110)(0101). The swapped nibbles would be (0101)(0110) same as decimal 86.

Input: $N = 18
Output: 33

Binary representation of decimal 18 is 10010 or as 2 nibbles (0001)(0010). The swapped nibbles would be (0010)(0001) same as decimal 33.

Solution

Whether the input integers are less than 255 or not doesn't make the task much easier. So, we will allow positive integers exceeding 255.

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

\[ \ldots b_{10} b_{9} b_{8} b_7 b_6 b_5 b_4 b_3 b_2 b_1 b_0 \]

Swapping the last two nibbles, we get:

\[ \ldots b_{10} b_{9} b_{8} b_3 b_2 b_1 b_0 b_7 b_6 b_5 b_4 \]

Now, we could take the number, get a binary representation, swap the two nibbles using a regular expression or substrings, and turn this back into a decimal number.

But we can achieve the same things by manipulating the bits directly. To do this, we first split the original number, which will call \(N\), into three parts:

\[ \begin{array}{rccccccccccc|rcrl} \ldots & b_{10} & b_9 & b_8 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & (N & \& & \sim & \text{0xFF}) \\ \ldots & 0 & 0 & 0 & b_7 & b_6 & b_5 & b_4 & 0 & 0 & 0 & 0 & (N & \& & & \text{0xF0}) \\ \ldots & 0 & 0 & 0 & 0 & 0 & 0 & 0 & b_3 & b_2 & b_1 & b_0 & (N & \& & & \text{0x0F}) \\ \hline \ldots & b_{10} & b_9 & b_8 & b_7 & b_6 & b_5 & b_4 & b_3 & b_2 & b_1 & b_0 & & & & \end{array} \]

We can now shift the bits of the latter two parts four positions to the right or left:

\[ \begin{array}{rccccccccccc|rcrlcc} \ldots & b_{10} & b_9 & b_8 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & (N & \& & \sim & \text{0xFF}) & & \\ \ldots & 0 & 0 & 0 & 0 & 0 & 0 & 0 & b_7 & b_6 & b_5 & b_4 & (N & \& & & \text{0xF0}) & >> & 4 \\ \ldots & 0 & 0 & 0 & b_3 & b_2 & b_1 & b_0 & 0 & 0 & 0 & 0 & (N & \& & & \text{0x0F}) & << & 4 \\ \hline \ldots & b_{10} & b_9 & b_8 & b_3 & b_2 & b_1 & b_0 & b_7 & b_6 & b_5 & b_4 & & & & \end{array} \]

We can now use a bitwise-or (|) or just plain addition to of the three parts above to get the final result.

Perl

With the input number in $_:

say + ($_ & ~0xFF) | ($_ & 0x0F) << 4 | ($_ & 0xF0) >> 4

Find the full program on GitHub.

AWK

AWK does not have bitwise operators. But we can replace each of bitwise operations with arithmetic. Here, the input number is in $1:

print (($1 - ($1 % 256)) + ($1 %  16) * 16 + int (($1 % 256) / 16))

Find the full program on GitHub.

Bash

With the input number in num:

echo $(((num & ~0xFF) | (num & 0x0F) << 4 | (num & 0xF0) >> 4))

Find the full program on GitHub.

bc

bc doesn't have bitwise operators either, so we use arithmetic. With the input number in num:

num - (num % 256) + (num % 16) * 16 + (num % 256) / 16

Find the full program on GitHub.

Befunge-93

There are no bitwise operations in Befunge-93, so we have to use arithmetic. Befunge-93 also limits numerical literals to single digits. And the language is stack based. This leads to:

& :1+!#@_ : 44* % 44** \ 44*/ + . 55+,

We start off by reading in a numeric value &.

We then check whether we're at end-of-file; in that case, the value read is -1. If so, we want to quit the program. First, we duplicate the value just read (:), add one to it (1+), and flip the resulting truth value (!). We skip the next command (#@), and then make a decision: if the top of the stack is false (which it is if we are not at end-of-file), we continue to the right, else we go left (_). If we go left, we exit the program (@).

If we go right, we can calculate the wanted value. First, we duplicate the top of the stack again (:). We then push 4 twice on the stack, and multiply the them, resulting in having 16 on top of the stack (44*). Now, we mod the (duplicate of) the read in value with the 16 on the top of the stack (%) — this is the value of the last nibble. We then multiply this value with 16 (44**).

We now have on the top of the stack the last nibble of the input value, shifted four bits the to left. The next value on the stack is the input value. We now swap the two values on top of the stack (\), and divide the top of the stack by 16 (44*/). Befunge-93 does integer division only, so we have the value of the penultimate nibble on top of the stack.

Since the second value of the stack is the last nibble shifted by four bits, we just have to add the two values to get the final result: (+), which we then print (.), followed by a newline (55+,) (a newline has ASCII value 10).

The program counter now automatically wraps to the beginning again, as the program is laid out on a torus.

Note that Befunge-93 only handles values up to 255, so we're not making any attempt to handle values exceeding 255.

Find the full program on GitHub.

C

With the input number in num:

printf ("%d\n", (num & ~0xFF) | (num & 0x0F) << 4 | (num & 0xF0) >> 4);

Find the full program on GitHub.

Go

Go doesn't have an unary operator to flip all the bits of its argument (~), but it does have a binary operator which does the same thing: (&^). With the input number in num:

fmt . Printf ("%d\n", (num &^ 0xFF) | (num & 0x0F) << 4 | (num & 0xF0) >> 4)

Find the full program on GitHub.

Java

With the input number in num:

System . out . println ((num & ~0xFF) | (num & 0x0F) << 4 | (num & 0xF0) >> 4);

Lua

Lua does not have bitwise operators. So, like AWK, we're using arithmetic. With the input number in num:

print (                (num - (num   % 0x100))
       +              ((num % 0x010) * 0x010)
       + math . floor ((num % 0x100) / 0x010))

Find the full program on GitHub.

Node.js

With the input number in num:

console . log ((+num & ~0xFF) | (+num & 0x0F) << 4 | (+num & 0xF0) >> 4)

Find the full program on GitHub.

Free Pascal

Free Pascal does have the standard bitwise operators, but they are named differently. It uses and, or and not where most languages use &, | and ~. To shift bits to the left or to the right, the operators shl and shr are used. Free Pascal uses a dollar ($) prefix to indicate hexadecimal literals.

Which leads to the following code, with the input number in num:

writeln ((num and not $FF) or (num and $0F) shl 4 or (num and $F0) shr 4);

Find the full program on GitHub.

Python

With the input number in num:

print ((num & ~0xFF) | (num & 0x0F) << 4 | (num & 0xF0) >> 4)

Find the full program on GitHub.

R

R does not have bitwise operators, but it does have bitwise functions. So our R solution is a bit more wordy. With the input number in num:

cat (bitwOr (bitwOr (bitwAnd (n, bitwNot (0xFF)),
                     bitwShiftL (bitwAnd (n, 0x0F), 4)),
                     bitwShiftR (bitwAnd (n, 0xF0), 4)), "\n")

Find the full program on GitHub.

Ruby

With the input number in num:

puts ((num & ~0xFF) | (num & 0x0F) << 4 | (num & 0xF0) >> 4)

Find the full program on GitHub.

Scheme

Scheme does not have bitwise operators, but bitwise functions. Bitwise or and bitwise and are named logior and logand, bitwise not is called lognot, and shifting bits is done with ash (arithmetic shift). A negative second argument to ash shifts to the right, else it shifts left.

Hexadecimal literals in Scheme are prefixed with #x.

This leads to, with the input number in num:

(format #t "~d\n" (logior (logand num (lognot #xFF))
                     (ash (logand num #x0F)  4)
                     (ash (logand num #xF0) -4)))

Find the full program on GitHub.

Tcl

With the input number in num:

puts [expr ($num & ~0xFF) | ($num & 0x0F) << 4 | ($num & 0xF0) >> 4]

Find the full program on GitHub.


Please leave any comments as a GitHub issue.