Negabinary base

The negabinary base, and in general any negative-base system, allows the representation of negative numbers without the need of using a minus sign.

Calculation by hand

To get some intuition about how this works, let’s consider the negabinary base (b = -2). In this base, each position represents a power of -2:

+16, -8, +4, -2, +1

and therefore:

0 = 0
1 = 1
2 = 110 4-2
3 = 111 4-2+1
4 = 100
5 = 101 4+1
6 = 11010 16-8-2

-1 = 11 -2+1
-2 = 10
-3 = 1101 -8+4+1
-4 = 1100 -8+4
-5 = 1111 -8+4-2+1
-6 = 1110 -8+4-2

Algorithm implementation

Binary expansion

Before jumping into the implementation of the negabinary representation, it’s worth reviewing the algorithm to get the binary expansion of a decimal number:

def binary_expansion(n):
    """
    Binary representation of n
    MSB (most significant bit) is in the leftmost position
    """
    b = 2
    digits = []
    while n > 0:
        n, r = divmod(n, b)
        digits.append(str(r))
    return "".join(digits[::-1])

This function is valid for any b such that 2 \le b \le 10 (for b > 10 new symbols are needed in addition to the numeric ones).

Now, can we use the same algorithm for b=-2? Let’s take a closer look.

The above algorithm relies on an implementation detail of the programming language, namely: for n, b > 0 the result of the integer division is rounded towards zero and that makes the remainder positive.

Let that sink in and take a look at this other post Do you really know how to use the modulo operator?

Different programming languages behave differently when calculating the integer division: Python performs a floored division that returns the largest integer less than or equal to the quotient, whereas Java does a truncated division that returns the integer part of the quotient.

When dividend and divisor are positive, then both divisions are equivalent, resulting in the quotient being rounded towards zero.

Negabinary expansion

Things are different in the realm of negative numbers though. For instance,

//Use case: positive number in negabinary

//Python
7/(-2) = (-4, -1)

//Java
7/(-2) = (-3, 1)
//Use case: negative number in negabinary

//Python
-7/(-2) = (3, -1)

//Java
-7/(-2) = (3, -1)

As a picture is worth a thousand words, here’s the above explanation in images.

  1. truncated division when dividend is positive
  2. floored division when dividend is positive
  3. division when dividend is negative, both divisions are equivalent
Integer division
Integer division

In order to avoid negative digits in the negabinary representation, we need to turn the remainders into positive values. According to the previous picture, that can be achieved by adding 1 to the quotient and subtracting the base from the remainder.

And now we are equipped to implement the algorithm of the negabinary expansion:

def negabinary_expansion(n):
    """
    Negabinary (base -2) representation of n
    MSB (most significant bit) is in the leftmost position
    """
    b = -2
    digits = []
    while n != 0:
        n, r = divmod(n, b)
        if r < 0:
            r -= b
            n += 1
        digits.append(str(r))
    return "".join(digits[::-1])

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.