---
title: "Polynomial Counting 1: A primer"
description: |
  An exploration into generalizations of positional number systems to irrational numbers.
format:
  html:
    html-math-method: katex
jupyter: python3
date: "2021-02-03"
date-modified: "2025-02-07"
categories:
  - algebra
  - phinary
  - python
---

The single most common method of representing numbers in the modern world is in *positional numeral system*.
Despite being taught in early grade school, it is the result of millennia of mathematical thought.

The decimal system we use today assigns integers to *expansions* consisting several symbols called
  *numerals* next to each other.
Each numeral is positioned at a *place value*, which has a value ten times greater than its neighbor
  to the right and a tenth as much of its neighbor to the left.
Due to place values sharing a constant ratio of ten, the system is called *decimal*.

$$
\begin{align*}
  \scriptsize 10^2 && \scriptsize 10^1 && \scriptsize 10^0 && \scriptsize 10^{-1}  &
  \quad \} \quad \text{Place values} \\
  4 && 3 && 2 .&& 1 &
  \quad \} \quad \text {Numerals: 1, 2, 3, 4} \\
  \hline
\end{align*} \\
\text{Four hundred, thirty-two, and one tenth}
$$

<details>
<summary>
On the difference between "1, 2, 3, and 4" and "one, two, three, and four"
</summary>
For clarity, I distinguish between numerals, such as "1", "2", "3", and "4", and numbers,
  such as "one", "two", "three", and "four".
When discussing different systems from decimal, it's easy to write things like "base 2" rather than "base two".
The former leverages a distinguished symbol for the number two existing, which while at times useful,
  leads to confusion between the symbol and the underlying number.
<!--After all, "every base is base 10".-->

When referring to its value, I'll tend to write out a number's English name, rather than
  how it would be written in decimal.
Conversely, when I want to refer to the symbols themselves, I will enclose them in quotes;
  for example, "0" refers to the symbol 0.
</details>


A Brief History
---------------

As mentioned, this practice is millenia old.

Arguably, the oldest common ancestor was used by the Babylonians (circa eighteenth century BC),
  who instead used a sexagesimal (base sixty) system.
It lacked a "decimal point" (more properly a sexagesimal point, *fractional separator*, or *radix point*).
This meant that a representation could equally as well refer to thirty (30) or one-half (1/2 = 30×60^-1^),
  or one hundred and eight thousand (108000 = 30×60^2^ ) in the same way we might consider
  five (5), one-half (1/2 = 5×10^-1^), and five-hundred (500 = 5×10^2^) to be similar in decimal.
It also lacked a "0" symbol to represent an empty place value; instead, empty place values were simply skipped.
Thus, the onus was on the arithmetician to properly align digits, maintain spacing, and correctly interpret results.
Despite these limitations, it was robust enough to develop basic trigonometry and
  [approximate the square root of 2](https://en.wikipedia.org/wiki/YBC_7289).

Later, Indian mathematics developed its own place value system -- this time in the familiar base ten --
  at least by the time of Aryabhata (4th century AD).
It introduced the empty "0" symbol that the Babylonian system lacked.
Eventually, this system made its way to Europe by means of the Arabs.
The 16th century Dutch engineer Simon Stevin was one of the first individuals to introduce a "decimal point".
Though modern notation differs slightly from his, it introduced (or perhaps re-introduced) a means of adding
  and multiplying numbers between integers.
Needless to say, it has become so popular as to become one of the most predominant ways to express numbers.

Later thought realized bases other than ten were possible; for example,
  [binary](https://en.wikipedia.org/wiki/Binary_number) (base two) due in part to Leibniz.
Stranger yet are non-integral bases, for example the complex base $2i$ due to Knuth.
However, I find bases which rely on *irrational* numbers to be the most interesting.

Staying Golden
--------------

The [*golden ratio*](https://en.wikipedia.org/wiki/Golden_ratio), a number with many apocryphal attributions,
  was a favorite of Greek mathematics.
As such, it was originally recognized in the context of geometry, long before the development of algebra.
It is constructed by dividing a line segment such that the ratio between the longer and shorter sub-segments
  is the same as the ratio between original segment and the longer sub-segment.

Phrased in modern algebraic language, the golden ratio *φ* is the unique positive root of the polynomial
  $x^2 - x - 1$, expressed as $\frac{1 + \sqrt 5}{2} \approx 1.618…$.
Despite its name, this number is ir**ratio**nal, since it cannot be represented as a **ratio** of integers.
Furthermore, raising it to any integral power does not produce an integer (left as an exercise to the reader).

It might seem inconceivable that one may obtain an integer (other than zero or one) by summing powers of *φ*.
However, base *φ* (also called phinary) does in fact exist.
Here is a list of (canonical) expansions up to 10

:::: {.row .text-center width="50%"}
::: {#canonical-phinary-table .column}

| *n* (Decimal) | *n* (Phinary) |
|--------------:|:-------------:|
|  0            |      0        |
|  1            |      1        |
|  2            |     10.01     |
|  3            |    100.01     |
|  4            |    101.01     |
|  5            |   1000.1001   |
|  6            |   1010.0001   |
|  7            |  10000.0001   |
|  8            |  10001.0001   |
|  9            |  10010.0101   |
|  10           |  10100.0101   |

:::
::::

We can obtain the entries on this list in two ways: naively (and imprecisely), or directly.


### The Naive Approach

In the most general sense, an expansion is just a sequence of integers, or digits.
We can recover the value by summing the products of the integers by their place values.
For example, a decimal number has the form

$$
\begin{align*}
  x &= ({a_n a_{n-1}... a_1 a_0})_{10} \\
    &= a_0 \cdot 10^0 + a_1 \cdot 10^1 + ... + a_{n-1} \cdot 10^{n-1} + a_n \cdot 10^{n}
\end{align*}
$$

where the $a_i$ are digits of the number.
Negative indices (corresponding to fractional values) may also be used, but have been omitted for horizontal space.

This equivalence means that we can convert to and from a particular base.
Naively, we might use the following "greedy" algorithm to derive the base-$b$ expansion
(also called a [β-expansion](https://en.wikipedia.org/wiki/Non-integer_base_of_numeration)) of a number $x$:

```{python}
from math import log, floor

def beta_expand_greedy(
  x: float,
  b: float,
  tol: float = 0.0001
) -> dict[int, int]:
  ret = {}

  while x > tol:                    # While we're not precise enough
    p = int(floor(log(x, b)))       # Get the place value p
    digit, new_x = divmod(x, b**p)  # Get the quotient and remainder from
                                    #   dividing by this place value
    ret[p] = int(digit)             # Place the digit in place value p
    x = new_x                       # Update the value of x and repeat

  return ret

```

As a demonstration, this algorithm, when run on a decimal number gives the same value:

```{python}
#| code-fold: true

def as_digits(digits: dict[int, int]) -> str:
  '''Convert a dictionary from `beta_expand_greedy` to a sequence of digits'''
  return "".join(
    str(digits.get(i, 0)) + ("." if i == 0 else "")
    for i in range(max(digits.keys()), min(digits.keys()) - 1, -1)
  )

one_thousand_two_hundred_thirty_four = 1234
print(
  "one_thousand_two_hundred_thirty_four =",
  as_digits(beta_expand_greedy(one_thousand_two_hundred_thirty_four, 10)),
  "in base 10"
)
```

There are three problems with this.

1.  It is inexact. `x` gets smaller, but we can only ever approximate the result.
    For numbers smaller than the tolerance, it is outright wrong.
    Due to the nature of the approximation, the result can also appear in an unexpected form:
    ```{python}
    #| code-fold: true

    phi = (5**0.5 + 1) / 2
    print("Expected:", "10100.0101")
    print("Got:     ", as_digits(beta_expand_greedy(10, phi)))
    ```

2. It relies on a transcendental function, the logarithm.
    - One may approximate this by repeated division, but in general, it is practical to use a
      floating-point function.

3. The arguments `x` and `b` are given as floating-point numbers.
   However, if `p` is always positive, we can instead use integer arithmetic, which is more precise.
   Generally, we need some form of fractional arithmetic.

Modern FPUs are make the last two items somewhat trivial, but they necessarily make the calculation approximate.
Fortunately for phinary, there is a direct method which remedies all these issues and produces exact
  results without floating-point operations.


### Deriving Expansions

Take another look at the canonical representations [above](#canonical-phinary-table).
Much like binary, phinary only requires the digits 0 and 1.
Another slightly less obvious fact is that the string "11" never occurs in the expansion.
This is because we can rewrite the polynomial as the following

$$
\begin{gather*}
  x - 2 = 0 \implies
  \left. \begin{align*}
    x &= 2 \\
    10_x &= 02
  \end{align*} \right\}
  & \text{Binary}
  \\ \\
  \varphi^2 - \varphi - 1 = 0 \implies
  \left. \begin{align*}
    \varphi^2 &= \varphi + 1 \\
    100_\varphi &= 11_\varphi
  \end{align*} \right \}
  & \text{Phinary}
\end{gather*}
$$

This shows a connection between polynomials and positional notation which is not at all obvious.
The second lines leverage positional notation in lieu of a symbol; their interpretation is
  exactly the same as the first line.

When we multiply or divide by ten in decimal (or two in binary), we shift the digits left or right.
Likewise, we may multiply or divide by *φ* on either side of the equation.
Thus, it is also true that

$$
\begin{gather*}
  \left. \begin{align*}
    2^2 &= 2\cdot 2 &&\iff&
    100_2 &= 20_2 \\
    1 &= 2\cdot 2^{-1} &&\iff&
    1_2 &= 0.2_2
  \end{align*}\right \}
  & \text{Binary}
  \\ \\
  \left. \begin{align*}
    \varphi^3 &= \varphi^2 + \varphi &&\iff&
    1000_\varphi &= 110_\varphi \\
    \varphi &= 1 + \frac 1 \varphi &&\iff&
    10_\varphi &= 1.1_\varphi
  \end{align*}\right \}
  & \text{Phinary}
\end{gather*}
$$

Since this relationship holds for any adjacent place values, it is analogous to "carrying" in base ten.
In decimal, we care if a single place value exceeds ten and increment the next place value
  (once for each multiple of ten).
In phinary, we care if there are two "1"s in adjacent place values, and can remove such occurrences
  by doing the same.

More generally, we can look at expansions not restricted to the symbols "0" and "1" and do similarly

$$
\begin{align*}
  32_\varphi &= 121_\varphi \\
  0.61_\varphi &= 1.5_\varphi
\end{align*}
$$

Thinking a little more cleverly, we can decompose 2 as

$$
\begin{align*}
  \textcolor{red}{2} = 1.\textcolor{red}{11}_\varphi =
  \textcolor{blue}{1.1}1_\varphi &= \textcolor{blue}{1}0.01_\varphi \\
  2 &= \varphi + \varphi^{-2}
\end{align*}
$$

With this rule in tow, we can finally start counting in phinary.
We count in base ten by incrementing the ones digit (or 0th place value) and carrying tens to higher digits.
In phinary, we have two carry rules, which we repeat until we cannot:

1. Express "011" as "100"
2. Express "0200" as "1001"

Aggressively applying these rules results in the same expansion as found in the
  [canonical table](#canonical-phinary-table).
For example, the expansion of three is clearly

$$
3 = 2 + 1 = 10.01_\varphi + 1 = \textcolor{red}{11}.01 = \textcolor{red}{1}00.01
$$

Both of these rules hold for larger digits as well.
For example, we can expand the quantity $4\varphi + 3$ as:

$$
\stackrel{\text{Carry 033 = 300}}{
  00\textcolor{red}{043}_\varphi =
  00\textcolor{red}{310}
}_\varphi =
\stackrel{\text{Carry 0200 = 1001}}{
  0\textcolor{blue}{0310}_\varphi =
  0\textcolor{blue}{1111}
}_\varphi =
0\textcolor{green}{11}\textcolor{orange}{11}_\varphi =
\textcolor{green}{1}0\textcolor{orange}{1}00_\varphi
$$

Checking approximately, this identity appears to be true:

```{python}
print(phi**4 + phi**2 - (4 * phi + 3))
```


### The Other Root

As a quadratic, the polynomial $x^2 - x - 1$ has two roots: $\varphi$ and its conjugate
  $\varphi^* = -\varphi^{-1}$.
This implies that each phinary string can be interpreted by either root.

$$
\begin{align*}
  5 = 1000.1001_{\varphi_{\phantom{*}}}
    &= \varphi^3 + \varphi^{-1} + \varphi^{-4} \\
  \phantom{5} = 1000.1001_{\varphi^*}
    &= ((-\varphi)^{-1})^3 + ((-\varphi)^{-1})^{-1} + ((-\varphi)^{-1})^{-4} \\
    &= \varphi^{4} -\ \varphi -\ \varphi^{-3} \\
    &= 10000_\varphi -\ 10.001_\varphi
\end{align*}
$$

To make the calculation easier, we can un-expand the postive part to make cancellation with the
  negative part easier.
This is the same as borrowing when doing typical subtraction.

$$
\begin{align*}
  10000_\varphi &= 1100_\varphi = 1011_\varphi = 1010.11_\varphi \\
    &= 1010.1011_\varphi
\end{align*}
$$

Proceeding onwards,

$$
\begin{align*}
  1000.1001_{\varphi^*} &= 10000_\varphi -\ 10.001_\varphi \\
    &= 1010.1011_\varphi -\ 10.001_\varphi \\
    &= 1000.1001_\varphi
\end{align*}
$$

And we breathe a sigh of relief since the expansion we get is the same we started with.
This is perhaps one of the reasons phinary expansions seem so verbose.

As an aside, since $-\varphi^{-1}$ is negative, its powers alternate between positive and negative.
Also, since its magnitude is less than one, place values to the right of the radix point are larger than one,
  the inverse of what one is used to with base ten.


Fibonacci and Zeckendorf
------------------------

Instead of assigning place values to powers of the base, we can instead imagine a situation where the
  place values correspond to the values of a sequence, in particular the Fibonacci numbers.
Phi also turns up when discussing this sequence, or more generally, sequences generated by the recurrence
  $a_{n+1} = a_n + a_{n-1}$.
This bears a striking resemblance the the polynomial mentioned above, with cursory examination by
  [generating functions](https://en.wikipedia.org/wiki/Generating_function) revealing the connection.

Fibonacci numbers are all integers, so sums of them can only express integers.
If we assign place values to unique Fibonacci numbers (one is "1" and not "10"), we can imagine a
  similar algorithm to the one presented earlier.
That is, we can derive an expansion for a number by subtracting out the largest Fibonacci number less than it
  (possibly multiple times) and repeating with the remainder.
Expansions of the integers up to 10 are:

:::: {.row .text-center width="50%"}
::: {#canonical-zeckendorf-table .column}

| *n* (Decimal) | *n* (Fibonacci) |
|--------------:|----------------:|
|  0            |      0          |
|  1            |      1          |
|  2            |     10          |
|  3            |    100          |
|  4            |    101          |
|  5            |   1000          |
|  6            |   1001          |
|  7            |   1010          |
|  8            |  10000          |
|  9            |  10001          |
|  10           |  10010          |

:::
::::

These are known as *Zeckendorf expansions*.

These representations seem very similar to the phinary strings above.
Not only that, but this sequence is also the sequence of all binary strings that do not contain two consecutive
  "1"s ([OEIS A014417](https://oeis.org/A014417)).
This representation is exactly as arbitrary as preferring the greedy phinary representation;
instead, this is the "greedy series expansion" of an integer in the Fibonacci numbers.


### Expanding Two, Again

Because of the relationship between phi and the Fibonacci numbers, we have the familiar relation

$$
\begin{align*}
  2 F_n &= F_{n+1} + F_{n-2} \\
  0200_\text{Zeck} &= 1001_\text{Zeck}
\end{align*}
$$

For small $n$, this identity seems wrong, but it can in fact be justified:

$$
\begin{array}{c|ccccc:cc}
  & 8 & 5 & 3 & 2 & 1 & 1 & \sim \\ \hline
  2 &   &   &   &   & 2 &   &    \\
    &   &   &   & 1 & 0 & 0 & 1  \\
    &   &   &   & 1 & 0          \\ \hline
  4 &   &   &   & 2 & 0 &   &    \\
    &   &   & 1 & 0 & 0 & 1 &    \\
    &   &   & 1 & 0 & 1
\end{array}
$$

In the expansion of 2, the rightmost "1" seems to underflow.
However, in the expansion of 4, we must consider the second "1" in the negative first place value.
It acts as a sort of temporary storage which is immediately transferred into place value zero.


Synthesis: Generalizing Phinary
-------------------------------

By starting with the golden ratio base, many natural questions arise.
Does this approach work with other quadratic roots?
Are there any restrictions on the coefficients (or sequences)?
Does it work with any polynomial with positive roots?
Are only monic polynomials allowed to be used?
What digits are minimally necessary to represent any integer?
How "canonical" can "canonical" really be?

Rather than answering these questions or giving proofs, I think it's best to lay some ground rules.
Using the above examples, I define two genera of positional number systems:

- A *fractional* number system is one where the place values are determined by the powers of the
    root of a polynomial with integer coefficients.
  The "fraction" in fractional comes allowing negative powers of our base.
  Therefore, we can represent rational numbers and use a fractional separator.
  - Naturally, the decimal system currently in use fits in here, corresponding to the polynomial $x - 10$.
  - Likewise, phinary corresponds to the polynomial $x^2 - x - 1$.

- An *integral* number system is one where the place values are given by a strictly increasing integral sequence.
  It can express only integers and there is no fractional separator.

  - As an example, the geometric series produced from an integer (e.g.: 1, 2, 4, 8, …), corresponds to
      a typical system without support for fractions.

  - The already-discussed the Fibonacci base fits here as well.
    In fact, since linear recurrence relations correspond to polynomials, this extends to a correspondence
      between integral and fractional systems.

  - Other sequences are also valid, like the square numbers.
    In the "square number base" we know the digital root (of canonical expansions) never exceeds 4 due to
    [Lagrange's four-square theorem](https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem).


### Alphabets

A positional number system not only has place values, but a *numeral alphabet*.
In standard decimal, there are ten distinct symbols including "0": {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}.
The choice of symbols is arbitrary
  (it can vary
  [with](https://en.wikipedia.org/wiki/Eastern_Arabic_numerals)
  [language](https://en.wikipedia.org/wiki/Chinese_numerals)),
  but each has a *weight*, the integer quantity assigned to them.
In the modern Western world,
  [Hindu-Arabic numerals](https://en.wikipedia.org/wiki/Hindu%E2%80%93Arabic_numeral_system) are standard
  and distinct from alphabetic characters, so the distinction between "weight" and "symbol" can be ignored
  by using them conventionally for the first ten whole numbers.
Subsets of this alphabet include the binary alphabet, {0, 1}, and the ternary alphabet, {0, 1, 2}.

A *minimal alphabet* for a number system is an alphabet of the smallest size which can still represent
  every integer.
It is most convenient to consider an alphabet of integers from 0 up to a particular value,
  even though it may be true that minimal alphabets might exist which "skip" over certain weights.

It is often useful to be able to borrow a symbol of a certain weight, even if it would not be present
  in a minimal alphabet (for example, using "2" when it is convenient to do so, as above).
In this manner, it is also possible to interpret the representation of a number in one base
  in another arbitrary base.

*Balanced alphabets* also exist, which contain negative numeral weights.
For example, the balanced ternary alphabet consists of the weights of {-1, 0, 1}.
Powers of 3 always determine the place values in ternary, but expansions change to suit the alphabet.
To conserve horizontal space, I'll use the symbols $\bar{1}$ and "T" to signify -1.


### Canonicity

Finding the *canonical expansion* of a number should be as simple as incrementing the 0th place value
  and aggressively applying the carry.
For fractional systems, this amounts to adding one the 1's digit, and for integral ones,
  adding it to the rightmost.

Note that irrational systems have at least *two* carry rules.
In phinary, these are the "011" = "100" rule, and the "0200" = "1001" rule.


### Questions About the Above Rules

One may take several exceptions with these definitions and the restrictions they impose,
  to which I will offer a brief dismissal:


<details>
<summary>
#### Why limit alphabet weights to integers?
</summary>

Integers and integer arithmetic are fundamental systems with very straightforward addition and multiplication.
Adding more complex rules by introducing fractions or polynomial roots creates unnecessary complications.
</details>


<details>
<summary>
#### Why prefer weights of integers from 0 to n?
</summary>

Alphabets are best kept inductive -- either a weight is the largest possible or its successor is also a weight.
If we start with a negative weight, this includes balanced alphabets.

Unbounded alphabets have their uses.
For example, we might hold off from carrying until necessary, or prefer expansions like
  $21_\varphi = 1 + 2\varphi$ to $21_\varphi = 1000_\varphi = \varphi^4$.

The inductive base case, the binary alphabet, is fairly important for two reasons:

- Expansions can always be padded with 0s to produce other valid expansions.
- If "1" does not exist in the alphabet, it should be derivable in some way from other symbols like "2" and "3".
</details>


<details>
<summary>
#### Do we prefer monic polynomials?
</summary>

The recurrence relation corresponding to a non-monic polynomials must cycle mod the leading term.
The simplest (only?) examples are just geometric series; in other words, normal integral systems.

For example, the powers of 3 satisfy $2a_{n+1} = 5a_n + 3a_{n-1}$. But the RHS simplifies:

$$
2a_{n+1} = 5a_n + 3a_{n-1} = 5a_n + a_n = 6a_n \\
a_{n+1} = 3a_n
$$

Incidentally, 3 is a root of $2x^2 - 5x - 3$.
Fermat's little theorem is likely a component in proving this generally.
</details>


<details>
<summary>
#### Why exclude transcendentals from fractional systems?
</summary>

Convergent series like $\exp{x}$ require coefficients which shrink quickly, far below a magnitude of 1.
This conflicts with our expectation of counting polynomials to be integral polynomials.
This is disappointing, since relatively simple transcendental like $e$
  (simple in terms of continued fractions, combinatorics, etc) relies on a series in rationals.
</details>


Closing
-------

With these restrictions in mind, I wrote a simple Haskell library to help explore these systems
  (found [here](https://github.com/queue-miscreant/GenBase)).
The [next post](../2) will discuss quadratic polynomials with larger coefficients than 1, and problems
  not discussed with higher expansions.
