Non-standard positional numeral system
A negative base (or negative radix) may be used to construct a non-standard positional numeral system. Like other place-value systems, each position holds multiples of the appropriate power of the system’s base; but that base is negative—that is to say, the base b is equal to −r for some natural number r (r ≥ 2).
Negative-base systems can accommodate all the same numbers as standard place-value systems, but both positive and negative numbers are represented without the use of a minus sign (or, in computer representation, a sign bit); this advantage is countered by an increased complexity of arithmetic operations. The need to store the information normally contained by a negative sign often results in a negative-base number being one digit longer than its positive-base equivalent.
The common names for negative-base positional numeral systems are formed by prefixing nega- to the name of the corresponding positive-base system; for example, negadecimal (base −10) corresponds to decimal (base 10), negabinary (base −2) to binary (base 2), negaternary (base −3) to ternary (base 3), and negaquaternary (base −4) to quaternary (base 4).^{[1]}^{[2]}
Example[edit]
Consider what is meant by the representation 12243 in the negadecimal system, whose base b is −10:
(−10)^{4} = 10,000 | (−10)^{3} = −1,000 | (−10)^{2} = 100 | (−10)^{1} = −10 | (−10)^{0} = 1 |
1 | 2 | 2 | 4 | 3 |
The representation 12,243_{−10} (which is intended to be negadecimal notation) is equivalent to 8,163_{10} in decimal notation, because 10,000 + (−2,000) + 200 + (−40) + 3 = 8,163.
- Remark
On the other hand, −8,163_{10} in decimal would be written 9,977_{−10} in negadecimal.
History[edit]
Negative numerical bases were first considered by Vittorio Grünwald in an 1885 monograph published in Giornale di Matematiche di Battaglini.^{[3]} Grünwald gave algorithms for performing addition, subtraction, multiplication, division, root extraction, divisibility tests, and radix conversion. Negative bases were later mentioned in passing by A. J. Kempner in 1936^{[4]} and studied in more detail by Zdzisław Pawlak and A. Wakulicz in 1957.^{[5]}
Negabinary was implemented in the early Polish computer BINEG (and UMC), built 1957–59, based on ideas by Z. Pawlak and A. Lazarkiewicz from the Mathematical Institute in Warsaw.^{[6]} Implementations since then have been rare.
Notation and use[edit]
Denoting the base as −r, every integer a can be written uniquely as
where each digit d_{k} is an integer from 0 to r − 1 and the leading digit d_{n} is > 0 (unless n = 0). The base −r expansion of a is then given by the string d_{n}d_{n−1}…d_{1}d_{0}.
Negative-base systems may thus be compared to signed-digit representations, such as balanced ternary, where the radix is positive but the digits are taken from a partially negative range. (In the table below the digit of value −1 is written as the single character T.)
Some numbers have the same representation in base −r as in base r. For example, the numbers from 100 to 109 have the same representations in decimal and negadecimal. Similarly,
and is represented by 10001 in binary and 10001 in negabinary.
Some numbers with their expansions in a number of positive and corresponding negative bases are:
Decimal | Negadecimal | Binary | Negabinary | Ternary | Negaternary | Balanced Ternary | Nega Balanced Ternary | Quaternary | Negaquaternary |
---|---|---|---|---|---|---|---|---|---|
−15 | 25 | −1111 | 110001 | −120 | 1220 | T110 | 11T0 | −33 | 1301 |
⋮ | |||||||||
−5 | 15 | −101 | 1111 | −12 | 21 | T11 | TT1 | −11 | 23 |
−4 | 16 | −100 | 1100 | −11 | 22 | TT | 1T | −10 | 10 |
−3 | 17 | −11 | 1101 | −10 | 10 | T0 | 10 | −3 | 11 |
−2 | 18 | −10 | 10 | −2 | 11 | T1 | 11 | −2 | 12 |
−1 | 19 | −1 | 11 | −1 | 12 | T | T | −1 | 13 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 2 | 10 | 110 | 2 | 2 | 1T | TT | 2 | 2 |
3 | 3 | 11 | 111 | 10 | 120 | 10 | T0 | 3 | 3 |
4 | 4 | 100 | 100 | 11 | 121 | 11 | T1 | 10 | 130 |
5 | 5 | 101 | 101 | 12 | 122 | 1TT | 11T | 11 | 131 |
6 | 6 | 110 | 11010 | 20 | 110 | 1T0 | 110 | 12 | 132 |
7 | 7 | 111 | 11011 | 21 | 111 | 1T1 | 111 | 13 | 133 |
8 | 8 | 1000 | 11000 | 22 | 112 | 10T | 10T | 20 | 120 |
9 | 9 | 1001 | 11001 | 100 | 100 | 100 | 100 | 21 | 121 |
10 | 190 | 1010 | 11110 | 101 | 101 | 101 | 101 | 22 | 122 |
11 | 191 | 1011 | 11111 | 102 | 102 | 11T | 1TT | 23 | 123 |
12 | 192 | 1100 | 11100 | 110 | 220 | 110 | 1T0 | 30 | 110 |
13 | 193 | 1101 | 11101 | 111 | 221 | 111 | 1T1 | 31 | 111 |
14 | 194 | 1110 | 10010 | 112 | 222 | 1TTT | TT1T | 32 | 112 |
15 | 195 | 1111 | 10011 | 120 | 210 | 1TT0 | TT10 | 33 | 113 |
16 | 196 | 10000 | 10000 | 121 | 211 | 1TT1 | TT11 | 100 | 100 |
17 | 197 | 10001 | 10001 | 122 | 212 | 1T0T | TT0T | 101 | 101 |
18 | 198 | 10010 | 10110 | 200 | 200 | 1T10 | TTT0 | 102 | 102 |
Note that, with the exception of nega balanced ternary, the base −r expansions of negative integers have an even number of digits, while the base −r expansions of the non-negative integers have an odd number of digits.
Calculation[edit]
The base −r expansion of a number can be found by repeated division by −r, recording the non-negative remainders in
${displaystyle {0,1,ldots ,r-1}}$, and concatenating those remainders, starting with the last. Note that if a / b is c with remainder d, then bc + d = a and therefore d = a − bc. To arrive at the correct conversion, the value for c must be chosen such that d is non-negative and minimal. For the fourth line of the following example this means that
has to be chosen — and not
${displaystyle =3~mathrm {remainder} ~4}$nor
${displaystyle =1~mathrm {remainder} ~-!2.}$
For example, to convert 146 in decimal to negaternary:
Reading the remainders backward we obtain the negaternary representation of 146_{10}: 21102_{–3}.
- Proof: (((2 · (–3) + 1) · (–3) + 1) · (–3) + 0) · (–3) + 2 = 146_{10}.
Note that in most programming languages, the result (in integer arithmetic) of dividing a negative number by a negative number is rounded towards 0, usually leaving a negative remainder. In such a case we have a = (−r)c + d = (−r)c + d − r + r = (−r)(c + 1) + (d + r). Because |d| < r, (d + r) is the positive remainder. Therefore, to get the correct result in such case, computer implementations of the above algorithm should add 1 and r to the quotient and remainder respectively.
Example implementation code[edit]
To negabinary[edit]
C#[edit]
static string ToNegabinary(int value)
{
string result = string.Empty;
while (value != 0)
{
int remainder = value % -2;
value = value / -2;
if (remainder < 0)
{
remainder += 2;
value += 1;
}
result = remainder.ToString() + result;
}
return result;
}
C++[edit]
auto to_negabinary(int value)
{
std::bitset<sizeof(int) * CHAR_BIT > result;
std::size_t bit_position = 0;
while (value != 0)
{
const auto div_result = std::div(value, -2);
if (div_result.rem < 0)
value = div_result.quot + 1;
else
value = div_result.quot;
result.set(bit_position, div_result.rem != 0);
++bit_position;
}
return result;
}
To negaternary[edit]
C#[edit]
static string negaternary(int value)
{
string result = string.Empty;
while (value != 0)
{
int remainder = value % -3;
value = value / -3;
if (remainder < 0)
{
remainder += 3;
value += 1;
}
result = remainder.ToString() + result;
}
return result;
}
Visual Basic .NET[edit]
Private Shared Function ToNegaternary(value As Integer) As String
Dim result As String = String.Empty
While value <> 0
Dim remainder As Integer = value Mod -3
value /= -3
If remainder < 0 Then
remainder += 3
value += 1
End If
result = remainder.ToString() & result
End While
Return result
End Function
Python[edit]
def negaternary(i: int) -> str:
"""Decimal to negaternary."""
if i == 0:
digits = ["0"]
else:
digits = []
while i != 0:
i, remainder = divmod(i, -3)
if remainder < 0:
i, remainder = i + 1, remainder + 3
digits.append(str(remainder))
return "".join(digits[::-1])
>>> negaternary(1000)
'2212001'
Common Lisp[edit]
(defun negaternary (i)
(if (zerop i)
"0"
(let ((digits "")
(rem 0))
(loop while (not (zerop i)) do
(progn
(multiple-value-setq (i rem) (truncate i -3))
(when (minusp rem)
(incf i)
(incf rem 3))
(setf digits (concatenate 'string (write-to-string rem) digits))))
digits)))
To any negative base[edit]
Java[edit]
public String negativeBase(int integer, int base) {
String result = "";
int number = integer;
while (number != 0) {
int i = number % base;
number /= base;
if (i < 0) {
i += Math.abs(base);
number++;
}
result = i + result;
}
return result;
}
AutoLisp[edit]
from [-10 -2] interval:
(defun negabase (num baz / dig rst)
;; NUM is any number. BAZ is any number in the interval [-10, -2].
;;
;; NUM and BAZ will be truncated to an integer if they're floats (e.g. 14.25
;; will be truncated to 14, -123456789.87 to -123456789, etc.).
(if (and (numberp num)
(numberp baz)
(<= (fix baz) -2)
(> (fix baz) -11))
(progn
(setq baz (float (fix baz))
num (float (fix num))
dig (if (= num 0) "0" ""))
(while (/= num 0)
(setq rst (- num (* baz (setq num (fix (/ num baz))))))
(if (minusp rst)
(setq num (1+ num)
rst (- rst baz)))
(setq dig (strcat (itoa (fix rst)) dig)))
dig)
(progn
(prompt
(cond
((and (not (numberp num))
(not (numberp baz)))
"nWrong number and negabase.")
((not (numberp num))
"nWrong number.")
((not (numberp baz))
"nWrong negabase.")
(t
"nNegabase must be inside [-10 -2] interval.")))
(princ))))
PHP[edit]
The conversion from integer to some negative base:
function toNegativeBase($no, $base)
{
$digits = array();
$base = intval($base);
while ($no != 0) {
$temp_no = $no;
$no = intval($temp_no / $base);
$remainder = ($temp_no % $base);
if ($remainder < 0) {
$remainder += abs($base);
$no++;
}
array_unshift($digits, $remainder);
}
return $digits;
}
Visual Basic .NET[edit]
Function toNegativeBase(Number As Integer , base As Integer) As System.Collections.Generic.List(Of Integer)
Dim digits As New System.Collections.Generic.List(Of Integer)
while Number <> 0
Dim remainder As Integer= Number Mod base
Number = CInt(Number / base)
if remainder < 0 then
remainder += system.math.abs(base)
Number+=1
end if
digits.Insert(0, remainder)
end while
return digits
end function
Shortcut calculation[edit]
The following algorithms assume that
- the input is available in bitstrings and coded in (base +2; digits in
- there are add (+) and xor (^) operations which operate on such bitstrings (as in most of today’s digital computers),
- the set
- the output is coded in the same bitstring format, but the meaning of the places is another one.
To negabinary[edit]
The conversion to negabinary (base −2; digits in
${displaystyle {0,1}}$) allows a remarkable shortcut
(C implementation):
unsigned int toNegaBinary(unsigned int value) // input in standard binary
{
unsigned int Schroeppel2 = 0xAAAAAAAA; // = 2/3*((2*2)^16-1) = ...1010
return (value + Schroeppel2) ^ Schroeppel2; // eXclusive OR
// resulting unsigned int to be interpreted as string of elements ε {0,1} (bits)
}
Due to D. Librik (Szudzik). The bitwise XOR portion is originally due to Schroeppel (1972).^{[7]}
JavaScript port for the same shortcut calculation:
function toNegaBinary(number) {
var Schroeppel2 = 0xAAAAAAAA;
// Convert to NegaBinary String
return ( ( number + Schroeppel2 ) ^ Schroeppel2 ).toString(2);
}
To negaquaternary[edit]
The conversion to negaquaternary (base −4; digits in
${displaystyle {0,1,2,3}}$) allows a similar shortcut (C implementation):
unsigned int toNegaQuaternary(unsigned int value) // input in standard binary
{
unsigned int Schroeppel4 = 0xCCCCCCCC; // = 4/5*((2*4)^8-1) = ...11001100 = ...3030
return (value + Schroeppel4) ^ Schroeppel4; // eXclusive OR
// resulting unsigned int to be interpreted as string of elements ε {0,1,2,3} (pairs of bits)
}
JavaScript port for the same shortcut calculation:
function toNegaQuaternary(number) {
var Schroeppel4 = 0xCCCCCCCC;
// Convert to NegaQuaternary String
return ( ( number + Schroeppel4 ) ^ Schroeppel4 ).toString(4);
}
Arithmetic operations[edit]
The following describes the arithmetic operations for negabinary; calculations in larger bases are similar.
Addition[edit]
Adding negabinary numbers proceeds bitwise, starting from the least significant bits; the bits from each addend are summed with the (balanced ternary) carry from the previous bit (0 at the LSB). This sum is then decomposed into an output bit and carry for the next iteration as show in the table:
Sum | Output | Comment | |||
---|---|---|---|---|---|
Bit | Carry | ||||
−2 | 010_{−2} | 0 | 1 | 01_{−2} | −2 occurs only during subtraction. |
−1 | 011_{−2} | 1 | 1 | 01_{−2} | |
0 | 000_{−2} | 0 | 0 | 00_{−2} | |
1 | 001_{−2} | 1 | 0 | 00_{−2} | |
2 | 110_{−2} | 0 | −1 | 11_{−2} | |
3 | 111_{−2} | 1 | −1 | 11_{−2} | 3 occurs only during addition. |
The second row of this table, for instance, expresses the fact that −1 = 1 + 1 × −2; the fifth row says 2 = 0 + −1 × −2; etc.
As an example, to add 1010101_{−2} (1 + 4 + 16 + 64 = 85) and 1110100_{−2} (4 + 16 − 32 + 64 = 52),
Carry: 1 −1 0 −1 1 −1 0 0 0 First addend: 1 0 1 0 1 0 1 Second addend: 1 1 1 0 1 0 0 + -------------------------- Number: 1 −1 2 0 3 −1 2 0 1 Bit (result): 1 1 0 0 1 1 0 0 1 Carry: 0 1 −1 0 −1 1 −1 0 0
so the result is 110011001_{−2} (1 − 8 + 16 − 128 + 256 = 137).
Another method[edit]
While adding two negabinary numbers, every time a carry is generated an extra carry should be propagated to next bit. Consider same example as above
Extra carry: 1 1 0 1 0 0 0 Carry: 1 0 1 1 0 1 0 0 0 First addend: 1 0 1 0 1 0 1 Second addend: 1 1 1 0 1 0 0 + -------------------------- Answer: 1 1 0 0 1 1 0 0 1
Negabinary full adder[edit]
A full adder circuit can be designed to add numbers in negabinary. The following logic is used to calculate the sum and carries:^{[8]}
Incrementing negabinary numbers[edit]
Incrementing a negabinary number can be done by using the following formula:^{[9]}
Subtraction[edit]
To subtract, multiply each bit of the second number by −1, and add the numbers, using the same table as above.
As an example, to compute 1101001_{−2} (1 − 8 − 32 + 64 = 25) minus 1110100_{−2} (4 + 16 − 32 + 64 = 52),
Carry: 0 1 −1 1 0 0 0 First number: 1 1 0 1 0 0 1 Second number: −1 −1 −1 0 −1 0 0 + -------------------- Number: 0 1 −2 2 −1 0 1 Bit (result): 0 1 0 0 1 0 1 Carry: 0 0 1 −1 1 0 0
so the result is 100101_{−2} (1 + 4 −32 = −27).
Unary negation, −x, can be computed as binary subtraction from zero, 0 − x.
Multiplication and division[edit]
Shifting to the left multiplies by −2, shifting to the right divides by −2.
To multiply, multiply like normal decimal or binary numbers, but using the negabinary rules for adding the carry, when adding the numbers.
First number: 1 1 1 0 1 1 0 Second number: 1 0 1 1 0 1 1 × ------------------------------------- 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 + ------------------------------------- Carry: 0 −1 0 −1 −1 −1 −1 −1 0 −1 0 0 Number: 1 0 2 1 2 2 2 3 2 0 2 1 0 Bit (result): 1 0 0 1 0 0 0 1 0 0 0 1 0 Carry: 0 −1 0 −1 −1 −1 −1 −1 0 −1 0 0
For each column, add carry to number, and divide the sum by −2, to get the new carry, and the resulting bit as the remainder.
Comparing negabinary numbers[edit]
It is possible to compare negabinary numbers by slightly adjusting a normal unsigned binary comparator. When comparing the numbers
${displaystyle A}$and
${displaystyle B}$, invert each odd positioned bit of both numbers.
After this, compare
and
${displaystyle B}$using a standard unsigned comparator.^{[10]}
Fractional numbers[edit]
Base −r representation may of course be carried beyond the radix point, allowing the representation of non-integer numbers.
As with positive-base systems, terminating representations correspond to fractions where the denominator is a power of the base; repeating representations correspond to other rationals, and for the same reason.
Non-unique representations[edit]
Unlike positive-base systems, where integers and terminating fractions have non-unique representations (for example, in decimal 0.999… = 1) in negative-base systems the integers have only a single representation. However, there do exist rationals with non-unique representations. For the digits {0, 1, …, t} with
${displaystyle mathbf {t} :=r!-!!1=-b!-!!1}$the biggest digit and
we have
So every number
${displaystyle {frac {1}{r+1}}+z}$with a terminating fraction
${displaystyle zin mathbb {Z} r^{mathbb {Z} }}$added has two distinct representations.
For example, in negaternary, i.e.
${displaystyle b=-3}$and
${displaystyle mathbf {t} =2}$, there is
Such non-unique representations can be found by considering the largest and smallest possible representations with integer parts 0 and 1 respectively, and then noting that they are equal. (Indeed, this works with any integer-base system.) The rationals thus non-uniquely expressible are those of form
with
${displaystyle z,iin mathbb {Z} .}$
Imaginary base[edit]
Just as using a negative base allows the representation of negative numbers without an explicit negative sign, using an imaginary base allows the representation of Gaussian integers. Donald Knuth proposed the quater-imaginary base (base 2i) in 1955.^{[11]}
See also[edit]
References[edit]
- ^ Knuth, Donald (1998), The Art of Computer Programming, Volume 2 (3rd ed.), pp. 204–205. Knuth mentions both negabinary and negadecimal.
- ^ The negaternary system is discussed briefly in Petkovšek, Marko (1990), “Ambiguous numbers are dense”, The American Mathematical Monthly, 97 (5): 408–411, doi:10.2307/2324393, ISSN 0002-9890, JSTOR 2324393, MR 1048915.
- ^ Vittorio Grünwald. Intorno all’aritmetica dei sistemi numerici a base negativa con particolare riguardo al sistema numerico a base negativo-decimale per lo studio delle sue analogie coll’aritmetica ordinaria (decimale), Giornale di Matematiche di Battaglini (1885), 203-221, 367
- ^ Kempner, A. J. (1936), “Anormal Systems of Numeration”, American Mathematical Monthly, 43 (10): 610–617, doi:10.2307/2300532, JSTOR 2300532, MR 1523792. The only reference to negative bases is a footnote on page 610, which reads, “Positive numbers less than 1 and negative numbers may be used as bases with slight modifications of the process and suitable restrictions on the set of digits employed.”
- ^ Pawlak, Z.; Wakulicz, A. (1957), “Use of expansions with a negative basis in the arithmometer of a digital computer”, Bulletin de l’Académie Polonaise des Sciences, Classe III, 5: 233–236.
- ^ Marczynski, R. W., “The First Seven Years of Polish Computing” Archived 2011-07-19 at the Wayback Machine, IEEE Annals of the History of Computing, Vol. 2, No 1, January 1980
- ^ See the MathWorld Negabinary link
- ^ Francis, Yu; Suganda, Jutamulia; Shizuhuo, Yin (4 September 2001). Introduction to Information Optics. Academic Press. p. 498. ISBN 9780127748115.
- ^ “Archived copy”. Retrieved 2016-08-29.
{{cite web}}
: CS1 maint: url-status (link) - ^ Murugesan, San (1977). “Negabinary arithmetic circuits using binary arithmetic”. IEE Journal on Electronic Circuits and Systems. 1 (2): 77. doi:10.1049/ij-ecs.1977.0005.
- ^ D. Knuth. The Art of Computer Programming. Volume 2, 3rd Edition. Addison-Wesley. pp. 205, “Positional Number Systems”