Positional Numeral System

Positional numeral system, also known as carry system, base system, positional notation, place-value notation, or positional numeral system, is a numeral system that can represent all natural numbers using a finite set of symbols. The number of symbols available in a positional system is called its radix or base. A positional system with radix nn is called the nn-ary system (n>1n>1); for example, the decimal system we use most often generally uses only the ten symbols 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 for notation. Carrying is the operation of “when a digit in some position reaches the base, set it to 0 and increment the digit in the next higher position.”

In general, we write a number in base nn as (ak⋯a1a0)n(a_k\cdots a_1a_0)_n, (ak⋯a1a0)(n)(a_k\cdots a_1a_0)_{(n)}, ak⋯a1a0(n){a_k\cdots a_1a_0}_{(n)}, ak⋯a1a0n{a_k\cdots a_1a_0}_{n}, and so on. If the base is implicit from the context, the subscript may be omitted. Note that ak⋯a1a0a_k\cdots a_1a_0 here is not the product of k+1k+1 numbers, but a sequence.

For a base-kk number an⋯a1a0a_n\cdots a_1a_0, its value is ankn+⋯+a1k1+a0k0=∑i=0naikia_nk^n+\cdots+a_1k^1+a_0k^0=\sum_{i=0}^n a_ik^i; for a number mm, suppose its representation in base kk is an⋯a1a0a_n\cdots a_1a_0. Then:

a0=m−q0k,q0=f(m/k),a1=q0−q1k,q1=f(q0/k),⋮⋮an=qn−1−qnk,qn=f(qn−1/k)=0,\begin{array}{cc} a_0=m-q_0k,&q_0=f(m/k),\\ a_1=q_0-q_1k,&q_1=f(q_0/k),\\ \vdots&\vdots\\ a_n=q_{n-1}-q_nk,&q_n=f(q_{n-1}/k)=0,\\ \end{array}

where f(x)=⌊x⌋f(x)=\lfloor x\rfloor.

The length of the representation of nn in base kk is ⌈log⁡k(n+1)⌉\lceil\log_k (n+1)\rceil.

We generally use a decimal point “..” to represent fractions1, a minus sign “−-” to represent negative numbers, and an overline over the final part of a decimal to represent an infinite repeating fraction. For readability, we may insert separators between groups of digits, such as spaces, ,,, or '; for example, 12 34512~345 represents 1234512345.

The positional systems commonly used in computers include binary, octal, and hexadecimal.

Conversion between positional systems

Decimal to other bases

We use binary as an example here; the principle is similar for other bases.

For the integer part, repeatedly divide the decimal number by 22 until the quotient is 00, then take the digits of all remainders from bottom to top; these are the digits of the binary integer part. For the fractional part, multiply it by 22, take the integer part of the result, and then repeat the process with the fractional part obtained from the calculation until the fractional part is all 00. Finally, take the integer parts obtained in each calculation from top to bottom; these are the digits of the binary fractional part.

Example

Convert 35.2535.25 to a binary number.

Integer part:

35/2=17…1,17/2=8…1,8/2=4…0,4/2=2…0,2/2=1…0,1/2=0…1.\begin{aligned} 35/2&=17 &\dots 1,\\ 17/2&=8 &\dots 1,\\ 8/2&=4 &\dots 0,\\ 4/2&=2 &\dots 0,\\ 2/2&=1 &\dots 0,\\ 1/2&=0 &\dots 1. \end{aligned}

Fractional part:

0.25×2=0.5…0,0.5×2=1…1.\begin{aligned} 0.25\times 2&=0.5 &\dots 0,\\ 0.5\times 2&=1 &\dots 1. \end{aligned}

Therefore, 35.25=(100011.01)235.25 = (100011.01)_2.

Implementation
#include <algorithm>
#include <string>

// only non-negative
// 2 <= base && base <= 36
std::string from_dec(int x, int base) {
  if (x == 0) return "0";
  std::string res;
  while (x) {
    int r = x % base;
    x /= base;

    // Method 1
    res.push_back(r < 10 ? '0' + r : 'A' + r - 10);
    // Method 2
    // const static std::string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    // res.push_back(digits[r]);
  }
  std::reverse(res.begin(), res.end());
  return res;
}

Other bases to decimal

Again, we use binary as an example. To convert a binary number to a decimal number, simply multiply the value of each digit by 2i2^i, where ii is the position of the current digit and the units digit has position 00.

Example

Convert (11010.01)2(11010.01)_{2} to a decimal number.

(11010.01)2=+ 1×24+1×23+0×22+1×21+0×20=+ 0×2−1+1×2−2=26.25.\begin{aligned} (11010.01)_{2}&=\phantom{+~}1\times 2^4+1\times 2^3+0\times 2^2+1\times 2^1+0\times 2^0\\ &\phantom{=}+~0\times 2^{-1}+1\times 2^{-2} \\ &=26.25. \end{aligned}

Thus, (11010.01)2=(26.25)10(11010.01)_2 = (26.25)_{10}.

Implementation
#include <cctype>
#include <string>

// only non-negative
// 2 <= base && base <= 36
int to_dec(std::string const& s, int base) {
  int res = 0;
  for (char c : s) {
    res *= base;
    if (isdigit(c))
      res += c - '0';
    else if (isupper(c))
      res += c - 'A' + 10;
    else if (islower(c))
      res += c - 'a' + 10;
  }
  return res;
}

Conversion among binary, octal, and hexadecimal

One octal digit can be represented by 3 binary digits (because 23=82^3 = 8), and one hexadecimal digit can be represented by 4 binary digits (24=162^4 = 16); the converse follows similarly.

Method of complements

See also: Ones' and two's complements

The method of complements is a method of representing negative numbers with positive numbers, so that subtraction can be computed using the same algorithms, circuits, or mechanical structures as addition with positive numbers. The method of complements is widely used in the design of calculators and computers to simplify their structure.

For an nn-digit base-bb number aa, its radix complement (also called the complement to bb) is bn−ab^n-a, while its diminished radix complement (also called the complement to b−1b-1, or simply the diminished complement) is bn−1−ab^n-1-a. In binary, the radix complement is called the complement to 22 (two's complement), also known as two's complement representation; the diminished radix complement is called the complement to 11 (ones' complement), also known as one's complement representation; in decimal, the radix complement is also called the complement to 1010 (ten's complement), and the diminished radix complement is also called the complement to 99 (nine's complement); other bases follow the same pattern.

For nn-digit base-bb numbers x,yx,y, when computing x−yx-y, we have the following methods (if the result exceeds nn digits, discard the higher digits):

  1. Consider the diminished complement x′=bn−1−xx'=b^n-1-x of xx, and compute x′+y=bn−1−x+yx'+y=b^n-1-x+y; the diminished complement of this result is the answer.
  2. Consider the diminished complement y′=bn−1−yy'=b^n-1-y of yy, and compute x+y′=bn−1+x−yx+y'=b^n-1+x-y; simply add one to obtain the answer.
  3. Consider the radix complement x′=bn−xx'=b^n-x of xx, and compute x′+y=bn−x+yx'+y=b^n-x+y; the radix complement of this result is the answer.
  4. Consider the radix complement y′=bn−yy'=b^n-y of yy, and compute x+y′=bn+x−yx+y'=b^n+x-y; this is the answer.

In addition, for a number in base kk, let d=k−1d=k-1. Then ⋯dd=:d‾=∑i=0∞dki=−1\cdots dd=:\overline{d}=\sum_{i=0}^{\infty} dk^i=-1. Therefore, for an nn-digit number xx, if its radix-complement representation in base kk is an−1⋯a1a0a_{n-1}\cdots a_1a_0, then d‾an−1⋯a1a0\overline{d}a_{n-1}\cdots a_1a_0 is ∑i=0n−1aiki+∑i=n∞dki=kn−x+(−kn)=−x\sum_{i=0}^{n-1}a_ik^i+\sum_{i=n}^{\infty} dk^i=k^n-x+(-k^n)=-x. This idea of “numbers with infinitely many digits” can be generalized to pp-adic numbers (pp-adic number).

Furthermore, we have an interesting theorem about complements and infinite repeating decimals:

Midy's theorem

Let aa be a positive integer and pp a positive prime. Suppose that the representation of a/pa/p in base bb is 0.a1a2⋯al‾0.\overline{a_1a_2\cdots a_l}, where ll is the (shortest) repetend length. If ll is even2, let l=2kl=2k. Then a1a2⋯aka_1a_2\cdots a_k is the diminished complement of ak+1ak+2⋯a2ka_{k+1}a_{k+2}\cdots a_{2k}, that is:

  • ai+ai+k=ba_i+a_{i+k}=b,
  • a1a2⋯ak+ak+1ak+2⋯a2k=bk−1a_1a_2\cdots a_k+a_{k+1}a_{k+2}\cdots a_{2k}=b^k-1.

More generally, if ll has a nontrivial factor kk, let l=nkl=nk. Then ∑i=0n−1aik+1aik+2⋯a(i+1)k\sum_{i=0}^{n-1}a_{ik+1}a_{ik+2}\cdots a_{(i+1)k} is a multiple of bk−1b^k-1.

Example

For 1/19=0.052 631 578 947 368 421‾=0.032 745‾(8)1/19=0.\overline{052~631~578~947~368~421}=0.\overline{032~745}_{(8)}, we have:

  • 052 631 578+947 368 421=999 999 999052~631~578+947~368~421=999~999~999,
  • 052+631+578+947+368+421=3×999052+631+578+947+368+421=3\times 999,
  • 032(8)+745(8)=777(8)032_{(8)}+745_{(8)}=777_{(8)},
  • 03(8)+27(8)+45(8)=77(8)03_{(8)}+27_{(8)}+45_{(8)}=77_{(8)}.
Proof

For the a,b,p,l,n,ka,b,p,l,n,k in the theorem, it is not difficult to see that 1≤a11\leq a1 and (a,p)=(b,p)=1(a,p)=(b,p)=1.

For an integer 0≤i<l0\leq i<l, let f(i)=bi⋅a/p−⌊bi⋅a/p⌋f(i)=b^i\cdot a/p-\lfloor b^i\cdot a/p\rfloor. We have

0<f(i)=0.\overline{a_{i+1}a_{i+2}\cdots a_{nk}a_1a_2\cdots a_i}<1 \implies 0<pf(i) $$ Note that $pf(i)\in\mathbf{N}_+$ and $pf(i)\equiv ab^i\pmod p$, so $pf(i)=ab^i\bmod p$. Let $S_n=\sum_{i=0}^{n-1}f(ik)=\sum_{i=0}^{n-1}0.\overline{a_{ik+1}a_{ik+2}\cdots a_{nk}a_1a_2\cdots a_{ik}}$. We can “exchange” some digits among the fractions (for example, $0.\overline{{\color{Orchid}{14}}{\color{RoyalBlue}{28}}{\color{YellowGreen}{57}}}+0.\overline{{\color{RoyalBlue}{28}}{\color{YellowGreen}{57}}{\color{Orchid}{14}}}+0.\overline{{\color{YellowGreen}{57}}{\color{Orchid}{14}}{\color{RoyalBlue}{28}}}=0.\overline{\color{Orchid}{141414}}+0.\overline{\color{RoyalBlue}{282828}}+0.\overline{\color{YellowGreen}{575757}}=0.\overline{\color{Orchid}{14}}+0.\overline{\color{RoyalBlue}{28}}+0.\overline{\color{YellowGreen}{57}}=14/99+28/99+57/99=1$), so

\begin{aligned} S_n&=\sum_{i=0}^{n-1}0.\overline{a_{ik+1}a_{ik+2}\cdots a_{(i+1)k}}\ &=\sum_{i=0}^{n-1}a_{ik+1}a_{ik+2}\cdots a_{(i+1)k}/\left(b^k-1\right), \end{aligned}

Consequently, Consequently,

pS_n=p\sum_{i=0}^{n-1}a_{ik+1}a_{ik+2}\cdots a_{(i+1)k}/\left(b^k-1\right)= \sum_{i=0}^{n-1} \left(ab^{ik}\bmod p\right),

Therefore, Therefore,

\sum_{i=0}^{n-1}a_{ik+1}a_{ik+2}\cdots a_{(i+1)k}=\left(b^k-1\right)\frac{\sum_{i=0}^{n-1} \left(ab^{ik}\bmod p\right)}{p}.

If $p\mid \left(b^k-1\right)$, note that

\left(b^k-1\right)a/p=a_1a_2\cdots a_k.\overline{a_{k+1}a_{k+2}\cdots a_{nk}a_1a_2\cdots a_k}-0.\overline{a_{1}a_{2}\cdots a_{nk}},

Then $a_{k+1}a_{k+2}\cdots a_{nk}a_1a_2\cdots a_k=a_{1}a_{2}\cdots a_{nk}$, and consequently $a_1a_2\cdots a_k=a_{k+1}a_{k+2}\cdots a_{2k}=\dots=a_{(n-1)k+1}a_{(n-1)k+2}\cdots a_{nk}$. Thus $0.\overline{a_1a_2\cdots a_l}=0.\overline{a_1a_2\cdots a_k}$, contradicting the definition of $l$, so $p\nmid \left(b^k-1\right)$. Hence there exists a positive integer $c=\dfrac{\sum_{i=0}^{n-1} \left(ab^{ik}\bmod p\right)}{p}$ such that

\sum_{i=0}^{n-1}a_{ik+1}a_{ik+2}\cdots a_{(i+1)k}=c\left(b^k-1\right).

Corollary

For the above b,n,k,pb,n,k,p, we have

∑i=0n−1bik≡0(modp).\sum_{i=0}^{n-1} b^{ik}\equiv 0\pmod p.

Generalized positional systems

In a standard positional system, the base bb is always a fixed positive number, and each digit is selected from bb different symbols to represent a nonnegative number (disregarding the decimal point and minus sign). In fact, many other numeral and positional systems have similar characteristics but do not fully satisfy the definition of a positional system. We call such systems generalized positional systems or non-standard positional numeral systems. Several common generalized positional systems are introduced below.

Bijective numeral systems

Standard positional systems cannot establish a bijection with the numbers they represent: for example, 11, 0101, and 001001 represent the same number3, whereas a bijective numeral system can establish a bijection with the numbers it represents.

Bijective base kk (k≥1k\geq 1) uses the set {1,2,…,k}\{1,2,\dots,k\} to represent each number uniquely, according to the following rules:

  1. The empty string represents 00;
  2. A nonempty string an⋯a1a0a_n\cdots a_1a_0 represents the number ankn+⋯+a1k1+a0k0=∑i=0naikia_nk^n+\cdots+a_1k^1+a_0k^0=\sum_{i=0}^n a_ik^i.

For a positive number mm, suppose its representation in bijective base kk is an⋯a1a0a_n\cdots a_1a_0. Then:

a0=m−q0k,q0=f(m/k),a1=q0−q1k,q1=f(q0/k),⋮⋮an=qn−1−qnk,qn=f(qn−1/k)=0,\begin{array}{cc} a_0=m-q_0k,&q_0=f(m/k),\\ a_1=q_0-q_1k,&q_1=f(q_0/k),\\ \vdots&\vdots\\ a_n=q_{n-1}-q_nk,&q_n=f(q_{n-1}/k)=0,\\ \end{array}

where f(x)=⌈x⌉−1f(x)=\lceil x\rceil-1.

For example, Microsoft Excel's column labels use bijective base 2626.

In the bijective numeral system, we have the unary numeral system, in which a nonempty string consists only of 11s, and the length of the string is the number it represents.

As in the discussion of the method of complements, in bijective base kk with k>1k>1, let d=k−1d=k-1. Then ⋯dd=:d‾=∑i=0∞dki=−1\cdots dd=:\overline{d}=\sum_{i=0}^{\infty} dk^i=-1, and therefore d‾k=0\overline{d}k=0. Thus, if the representation of xx in bijective base kk is an−1⋯a1a0a_{n-1}\cdots a_1a_0, then d‾kan−1⋯a1a0\overline{d}ka_{n-1}\cdots a_1a_0 is −x-x.

Here are some properties of bijective base-kk numbers:

  • There are klk^l numbers of length l≥0l\geq 0.
  • When k≥2k\geq 2, the length of the representation of nn in bijective base kk is ⌊log⁡k(n+1)(k−1)⌋\lfloor\log_k (n+1)(k-1)\rfloor.
  • When k≥2k\geq 2, if the representation of a number nn in base kk contains no 00, then its representation in base kk is the same as its representation in bijective base kk.

The code for converting bijective base kk to decimal is the same as the code for converting base kk to decimal. Below is a reference implementation for converting decimal to bijective base kk.

Implementation
#include <algorithm>
#include <string>

// only non-negative
// 1 <= base && base < 36
std::string from_dec_bi(int x, int base) {
  std::string res;
  while (x > 0) {
    int q = (x + base - 1) / base - 1, r = x - q * base;
    x = q;

    // Method 1
    res.push_back(r < 10 ? '0' + r : 'A' + r - 10);
    // Method 2
    // const static std::string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    // res.push_back(digits[r]);
  }
  std::reverse(res.begin(), res.end());
  return res;
}

Signed-digit bases

Some positional systems allow negative numbers to occur as digits, such as balanced ternary.

Gray code

Main article: Gray code

Gray code is also called cyclic binary code or reflected binary code (reflected binary code, RBC). It is a special binary numeral system, commonly used for data checking.

Non-positive bases

We know that for a base-kk number an⋯a1a0a_n\cdots a_1a_0, its value is ∑i=0naiki\sum_{i=0}^n a_ik^i. With a slight modification, we can define a base-−k-k number an⋯a1a0(−k){a_n\cdots a_1a_0}_{(-k)} to represent ∑i=0nai(−k)i\sum_{i=0}^n a_i(-k)^i, where an,…,a1,a0∈{0,1,…,k−1}a_n,\dots,a_1,a_0\in \{0,1,\dots,k-1\}. For example, 12345(−10)=8265(10)12345_{(-10)}=8265_{(10)}. This positional system is called a negative-base system.

Similarly, we can define a complex-base system, such as a 2i2\mathrm{i} base system (quater-imaginary base, quater-imaginary numeral system). We can also define a non-integer base of numeration for the β\beta-expansion (β\beta-expansion) of real numbers.

Mixed-radix systems

In a standard positional system, the base corresponding to every digit is fixed, while a mixed-radix system allows each digit to correspond to a different base. The most common application of mixed-radix systems is timekeeping: hours use base 2424, while minutes and seconds use base 6060.

The number represented by an⋯a1a0a_n\cdots a_1a_0 in base bb is ∑i=0naibi\sum_{i=0}^n a_ib^i, while in a mixed-radix system it is ∑i=0nai∏j=0i−1bj\sum_{i=0}^n a_i\prod_{j=0}^{i-1}b_j, where bjb_j is the base corresponding to aja_j.

In algorithmic competitions, the most common mixed-radix system is the factorial number system, whose numbers can be written as an⋯a1a0 !{a_n\cdots a_1a_0}_{~!} and whose value is ∑i=0naii!\sum_{i=0}^na_i i!4. For applications of the factorial number system in algorithmic competitions, see Lehmer code/Cantor expansion.

Implementation (decimal to factorial number system)
#include <algorithm>
#include <string>

// only non-negative
std::string from_dec_factorial(int x) {
  if (x == 0) return "0";
  std::string res;
  int base = 1;
  while (x) {
    int r = x % base;
    x /= base++;

    // Method 1
    res.push_back(r < 10 ? '0' + r : 'A' + r - 10);
    // Method 2
    // const static std::string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    // res.push_back(digits[r]);
  }
  std::reverse(res.begin(), res.end());
  return res;
}
Implementation (factorial number system to decimal)
#include <cctype>
#include <string>

// only non-negative
int to_dec_factorial(std::string const& s) {
  int res = 0, base = s.size();
  for (char c : s) {
    res *= base--;
    if (isdigit(c))
      res += c - '0';
    else if (isupper(c))
      res += c - 'A' + 10;
    else if (islower(c))
      res += c - 'a' + 10;
  }
  return res;
}

Implementation in C++

For nonnegative numbers, C++ uses <前缀><数位><后缀> to represent an integer literal, where <数位> and <后缀> may both be empty. <后缀> indicates the type of the literal: for example, u or U indicates that the literal is unsigned, while l or L indicates that it is long, and so on. For <前缀>:

  • When <前缀> is 0x or 0X, it denotes a hexadecimal literal, and the characters in <数位> can only be selected from 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, A, b, B, c, C, d, D, e, E, f, F. For example, 0x1234ABCD is 1234ABCD(16)=305 441 741\text{1234ABCD}_{(16)}=305~441~741;
  • When <前缀> is 0, it denotes an octal literal, and the characters in <数位> can only be selected from 0, 1, 2, 3, 4, 5, 6, 7. For example, 01234567 is 1234567(8)=3423911234567_{(8)}=342391; 5
  • When <前缀> is 1, 2, 3, 4, 5, 6, 7, 8, or 9, it denotes a decimal literal, and the characters in <数位> can only be selected from 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
  • Since C++14, when <前缀> is 0b or 0B, it denotes a binary literal, and the characters in <数位> can only be selected from 0, 1. For example, 0b11001010 is 11001010(2)=20211001010_{(2)}=202.

References and notes

Footnotes

  1. Some regions use “,,” as the decimal point. ↩

  2. When a=1a=1, the sequence of primes satisfying this condition in decimal is A028416. ↩

  3. We call the 00s before the highest non-00 digit leading zeros (leading zero). Similarly, we can define trailing zeros (trailing zero). ↩

  4. The base corresponding to aia_i is i+1i+1, and 0≤ai≤i0\leq a_i\leq i. Note that (n+1)!−n!=n⋅n!(n+1)!-n!=n\cdot n!, so the representation of a number in the factorial number system is unique after leading zeros are removed. ↩

  5. 0 is an octal literal. ↩

This content comes from OI Wiki: Positional Numeral System. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.