Project P124

Pascal's triangle

Rows built from the one above by addition, every entry exact however long, checked by symmetry, the sum 2^n, the hockey stick and the count of odd entries; and the float formula's first mistake, in row 55.

2 modules · 2 recorded sessionstext-menu UI in the terminalupdated 2026-10-17

Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.

About

Each row built from the one above by addition, so every entry is exact however many digits it has.

  • main.eml - the menu, the triangle, one row with its checks, one entry beside the float formula, the float formula's first mistake, and the odd entries
  • triangle.eml - the rows, powers of two, the 1s of a number in binary, the checks, and the float formula

How each part works:

  • As in the corpus cases pascals-triangle and pascal-row-exact, a row is the row above with neighbours added: no division, so nothing to round. C(80, 40) has 24 digits, C(300, 150) has 89.
  • The checks on a row tie it to things worked out another way: - it is symmetric, C(n, k) = C(n, n - k); - its entries add up to 2^n exactly; - the hockey stick, C(k, k) + ... + C(n, k) = C(n + 1, k + 1), ties it to the next row; - it has 2^(the number of 1s in n in binary) odd entries.
  • The multiplicative formula in floats, C(n, k) = C(n, k - 1) * (n - k + 1) / k, is exact up to row 54. In row 55 it gives C(55, 26) as 3560597348629859.5 instead of 3560597348629860. That entry is below 2^53, but the product before the division is not.
  • The odd entries of rows 0 to 31 make Sierpinski's triangle.

What is checked: menu choices 1 to 6; a last row from 0 to 15; a row or an n from 0 to 300, and a k from 0 to n. An empty answer cancels.

Sessions: sessions/basic.in gives: - the triangle to row 8; - rows 10 and 80, with their checks; - C(55, 26), where the float formula is wrong, and C(300, 150); - the floats, and the odd entries.

sessions/bad-input.in gives: - menu choices 0 and x; - last rows: a cancel, 16, x and -1; - rows 301 and 1000; - entries: n 5 with k 6 and a cancel, and C(0, 0).

Built on the verified corpus cases pascals-triangle (each row grown from the one before) and pascal-row-exact (a row far past float precision, checked against global properties).

Recorded sessions

What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.

bad-input

interpreter: byte-equal
== Pascal's triangle ==
Each row built from the one above by addition, every entry exact however long.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 0
Pick a number from 1 to 6.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> x
Pick a number from 1 to 6.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 1
last row (0 to 15)> 
Cancelled.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 1
last row (0 to 15)> 16
Type a whole number from 0 to 15.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 1
last row (0 to 15)> x
Type a whole number from 0 to 15.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 1
last row (0 to 15)> -1
Type a whole number from 0 to 15.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 2
row (0 to 300)> 301
Type a whole number from 0 to 300.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 2
row (0 to 300)> 1000
Type a whole number from 0 to 300.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 3
n (0 to 300)> 5
k (0 to 5)> 6
Type a whole number from 0 to 5.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 3
n (0 to 300)> 5
k (0 to 5)> 
Cancelled.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 3
n (0 to 300)> 0
k (0 to 0)> 0
C(0, 0) = 1
  The float formula gets it exactly: 1.0

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 6
Bye.
What was typed (24 lines)
0
x
1

1
16
1
x
1
-1
2
301
2
1000
3
5
6
3
5

3
0
0
6

basic

interpreter: byte-equal
== Pascal's triangle ==
Each row built from the one above by addition, every entry exact however long.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 1
last row (0 to 15)> 8
          1
         1 1
        1 2 1
       1 3 3 1
      1 4 6 4 1
    1 5 10 10 5 1
   1 6 15 20 15 6 1
 1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 2
row (0 to 300)> 10
Row 10: 1 10 45 120 210 252 210 120 45 10 1
  symmetric: C(n, k) = C(n, n - k) for every k
  the entries add up to 2^10 exactly
  hockey stick: C(k, k) + C(k + 1, k) + ... + C(10, k) = C(11, k + 1) for every k
  4 odd entries; 10 in binary has 2 ones, and 2^2 = 4

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 2
row (0 to 300)> 80
Row 80 has 81 entries; it starts 1, 80, 3160.
The middle one, C(80, 40), has 24 digits:
  107507208733336176461620
  symmetric: C(n, k) = C(n, n - k) for every k
  the entries add up to 2^80 exactly
  hockey stick: C(k, k) + C(k + 1, k) + ... + C(80, k) = C(81, k + 1) for every k
  4 odd entries; 80 in binary has 2 ones, and 2^2 = 4

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 3
n (0 to 300)> 55
k (0 to 55)> 26
C(55, 26) = 3560597348629860 (16 digits)
  The float formula gives 3560597348629859.5.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 3
n (0 to 300)> 300
k (0 to 300)> 150
C(300, 150) = 93759702772827452793193754439064084879232655700081358920472352712975170021839591675861424 (89 digits)
  The float formula gives 9.375970277282747e+88.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 4
The multiplicative formula in floats: C(n, k) = C(n, k - 1) * (n - k + 1) / k.
It is exact up to row 54, and first goes wrong in row 55:
  C(55, 26) comes out 3560597348629859.5, and is 3560597348629860.
  That entry is below 2^53 = 9007199254740992, but the product before the division,
  92575531064376360, is not.
Building each row from the one above by addition needs no division, and is exact.

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 5
Rows 0 to 31, # for an odd entry:
                               #
                              # #
                             # . #
                            # # # #
                           # . . . #
                          # # . . # #
                         # . # . # . #
                        # # # # # # # #
                       # . . . . . . . #
                      # # . . . . . . # #
                     # . # . . . . . # . #
                    # # # # . . . . # # # #
                   # . . . # . . . # . . . #
                  # # . . # # . . # # . . # #
                 # . # . # . # . # . # . # . #
                # # # # # # # # # # # # # # # #
               # . . . . . . . . . . . . . . . #
              # # . . . . . . . . . . . . . . # #
             # . # . . . . . . . . . . . . . # . #
            # # # # . . . . . . . . . . . . # # # #
           # . . . # . . . . . . . . . . . # . . . #
          # # . . # # . . . . . . . . . . # # . . # #
         # . # . # . # . . . . . . . . . # . # . # . #
        # # # # # # # # . . . . . . . . # # # # # # # #
       # . . . . . . . # . . . . . . . # . . . . . . . #
      # # . . . . . . # # . . . . . . # # . . . . . . # #
     # . # . . . . . # . # . . . . . # . # . . . . . # . #
    # # # # . . . . # # # # . . . . # # # # . . . . # # # #
   # . . . # . . . # . . . # . . . # . . . # . . . # . . . #
  # # . . # # . . # # . . # # . . # # . . # # . . # # . . # #
 # . # . # . # . # . # . # . # . # . # . # . # . # . # . # . #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit
choice> 6
Bye.
What was typed (15 lines)
1
8
2
10
2
80
3
55
26
3
300
150
4
5
6

Modules

The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.

main.eml(entry)

eml
# P124 Pascal's triangle: the triangle, one row exactly, one entry, the
# checks on a row, the float formula's first mistake, and the odd entries.
import triangle

def plain(s):
    0 => i
    len(s) => j
    while i < j and s[i] == " ":
        i + 1 => i
    while j > i and s[j - 1] == " ":
        j - 1 => j
    return s[i:j]

def lpad(s, n):
    s => out
    while len(out) < n:
        " " + out => out
    return out

def spaces(n):
    "" => out
    for i in [1:n]:
        out + " " => out
    return out

def ask_number(prompt, high):
    plain(input(prompt)) => t
    if t == "":
        "Cancelled." ^0
        return 0 - 1
    if len(t) > 3:
        ("Type a whole number from 0 to " + str(high) + ".") ^0
        return 0 - 1
    for c in t:
        if c < "0" or c > "9":
            ("Type a whole number from 0 to " + str(high) + ".") ^0
            return 0 - 1
    if int(t) > high:
        ("Type a whole number from 0 to " + str(high) + ".") ^0
        return 0 - 1
    return int(t)

def row_text(r):
    "" => out
    for x in r:
        if out != "":
            out + " " => out
        out + str(x) => out
    return out

def show_triangle():
    ask_number("last row (0 to 15)> ", 15) => n
    if n < 0:
        return
    triangle.rows(n) => rs
    len(row_text(rs[n])) => w
    for r in rs:
        row_text(r) => t
        (spaces(int((w - len(t)) / 2)) + t) ^0

def one_row():
    ask_number("row (0 to 300)> ", 300) => n
    if n < 0:
        return
    triangle.row(n) => r
    if n <= 20:
        ("Row " + str(n) + ": " + row_text(r)) ^0
    else:
        int(n / 2) => m
        ("Row " + str(n) + " has " + str(n + 1) + " entries; it starts " + str(r[0]) + ", " + str(r[1]) + ", " + str(r[2]) + ".") ^0
        ("The middle one, C(" + str(n) + ", " + str(m) + "), has " + str(triangle.digits(r[m])) + " digits:") ^0
        ("  " + str(r[m])) ^0
    report(n)

def report(n):
    triangle.checks(n) => c
    if c[0]:
        "  symmetric: C(n, k) = C(n, n - k) for every k" ^0
    else:
        "  NOT symmetric" ^0
    if c[1]:
        ("  the entries add up to 2^" + str(n) + " exactly") ^0
    else:
        ("  the entries do NOT add up to 2^" + str(n)) ^0
    if c[2]:
        ("  hockey stick: C(k, k) + C(k + 1, k) + ... + C(" + str(n) + ", k) = C(" + str(n + 1) + ", k + 1) for every k") ^0
    else:
        "  the hockey stick does NOT hold" ^0
    ("  " + str(c[3]) + " odd entries; " + str(n) + " in binary has " + str(triangle.ones(n)) + " ones, and 2^" + str(triangle.ones(n)) + " = " + str(c[4])) ^0

def entry():
    ask_number("n (0 to 300)> ", 300) => n
    if n < 0:
        return
    ask_number("k (0 to " + str(n) + ")> ", n) => k
    if k < 0:
        return
    triangle.row(n)[k] => x
    if triangle.digits(x) == 1:
        ("C(" + str(n) + ", " + str(k) + ") = " + str(x)) ^0
    else:
        ("C(" + str(n) + ", " + str(k) + ") = " + str(x) + " (" + str(triangle.digits(x)) + " digits)") ^0
    triangle.float_entry(n, k) => f
    if f == x:
        ("  The float formula gets it exactly: " + str(f)) ^0
    else:
        ("  The float formula gives " + str(f) + ".") ^0

def floats():
    triangle.first_float_miss(200) => m
    "The multiplicative formula in floats: C(n, k) = C(n, k - 1) * (n - k + 1) / k." ^0
    ("It is exact up to row " + str(m[0] - 1) + ", and first goes wrong in row " + str(m[0]) + ":") ^0
    ("  C(" + str(m[0]) + ", " + str(m[1]) + ") comes out " + str(m[2]) + ", and is " + str(m[3]) + ".") ^0
    ("  That entry is below 2^53 = " + str(triangle.power_of_two(53)) + ", but the product before the division,") ^0
    ("  " + str(m[4]) + ", is not.") ^0
    "Building each row from the one above by addition needs no division, and is exact." ^0

def odd_pattern():
    "Rows 0 to 31, # for an odd entry:" ^0
    triangle.rows(31) => rs
    for r in rs:
        "" => t
        for x in r:
            if t != "":
                t + " " => t
            if x % 2 == 1:
                t + "#" => t
            else:
                t + "." => t
        (spaces(31 - len(r) + 1) + t) ^0

"== Pascal's triangle ==" ^0
"Each row built from the one above by addition, every entry exact however long." ^0
True => running
while running:
    "" ^0
    "1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit" ^0
    plain(input("choice> ")) => choice
    if choice == "1":
        show_triangle()
    elif choice == "2":
        one_row()
    elif choice == "3":
        entry()
    elif choice == "4":
        floats()
    elif choice == "5":
        odd_pattern()
    elif choice == "6":
        False => running
    else:
        "Pick a number from 1 to 6." ^0
"Bye." ^0
Python projection (main.py)
import triangle

def plain(s):
    i = 0
    j = len(s)
    while i < j and s[i] == " ":
        i = i + 1
    while j > i and s[j - 1] == " ":
        j = j - 1
    return s[i:j]

def lpad(s, n):
    out = s
    while len(out) < n:
        out = " " + out
    return out

def spaces(n):
    out = ""
    for i in range(1, n+1):
        out = out + " "
    return out

def ask_number(prompt, high):
    t = plain(input(prompt))
    if t == "":
        print("Cancelled.")
        return 0 - 1
    if len(t) > 3:
        print("Type a whole number from 0 to " + str(high) + ".")
        return 0 - 1
    for c in t:
        if c < "0" or c > "9":
            print("Type a whole number from 0 to " + str(high) + ".")
            return 0 - 1
    if int(t) > high:
        print("Type a whole number from 0 to " + str(high) + ".")
        return 0 - 1
    return int(t)

def row_text(r):
    out = ""
    for x in r:
        if out != "":
            out = out + " "
        out = out + str(x)
    return out

def show_triangle():
    n = ask_number("last row (0 to 15)> ", 15)
    if n < 0:
        return
    rs = triangle.rows(n)
    w = len(row_text(rs[n]))
    for r in rs:
        t = row_text(r)
        print(spaces(int((w - len(t)) / 2)) + t)

def one_row():
    n = ask_number("row (0 to 300)> ", 300)
    if n < 0:
        return
    r = triangle.row(n)
    if n <= 20:
        print("Row " + str(n) + ": " + row_text(r))
    else:
        m = int(n / 2)
        print("Row " + str(n) + " has " + str(n + 1) + " entries; it starts " + str(r[0]) + ", " + str(r[1]) + ", " + str(r[2]) + ".")
        print("The middle one, C(" + str(n) + ", " + str(m) + "), has " + str(triangle.digits(r[m])) + " digits:")
        print("  " + str(r[m]))
    report(n)

def report(n):
    c = triangle.checks(n)
    if c[0]:
        print("  symmetric: C(n, k) = C(n, n - k) for every k")
    else:
        print("  NOT symmetric")
    if c[1]:
        print("  the entries add up to 2^" + str(n) + " exactly")
    else:
        print("  the entries do NOT add up to 2^" + str(n))
    if c[2]:
        print("  hockey stick: C(k, k) + C(k + 1, k) + ... + C(" + str(n) + ", k) = C(" + str(n + 1) + ", k + 1) for every k")
    else:
        print("  the hockey stick does NOT hold")
    print("  " + str(c[3]) + " odd entries; " + str(n) + " in binary has " + str(triangle.ones(n)) + " ones, and 2^" + str(triangle.ones(n)) + " = " + str(c[4]))

def entry():
    n = ask_number("n (0 to 300)> ", 300)
    if n < 0:
        return
    k = ask_number("k (0 to " + str(n) + ")> ", n)
    if k < 0:
        return
    x = triangle.row(n)[k]
    if triangle.digits(x) == 1:
        print("C(" + str(n) + ", " + str(k) + ") = " + str(x))
    else:
        print("C(" + str(n) + ", " + str(k) + ") = " + str(x) + " (" + str(triangle.digits(x)) + " digits)")
    f = triangle.float_entry(n, k)
    if f == x:
        print("  The float formula gets it exactly: " + str(f))
    else:
        print("  The float formula gives " + str(f) + ".")

def floats():
    m = triangle.first_float_miss(200)
    print("The multiplicative formula in floats: C(n, k) = C(n, k - 1) * (n - k + 1) / k.")
    print("It is exact up to row " + str(m[0] - 1) + ", and first goes wrong in row " + str(m[0]) + ":")
    print("  C(" + str(m[0]) + ", " + str(m[1]) + ") comes out " + str(m[2]) + ", and is " + str(m[3]) + ".")
    print("  That entry is below 2^53 = " + str(triangle.power_of_two(53)) + ", but the product before the division,")
    print("  " + str(m[4]) + ", is not.")
    print("Building each row from the one above by addition needs no division, and is exact.")

def odd_pattern():
    print("Rows 0 to 31, # for an odd entry:")
    rs = triangle.rows(31)
    for r in rs:
        t = ""
        for x in r:
            if t != "":
                t = t + " "
            if x % 2 == 1:
                t = t + "#"
            else:
                t = t + "."
        print(spaces(31 - len(r) + 1) + t)

print("== Pascal's triangle ==")
print("Each row built from the one above by addition, every entry exact however long.")
running = True
while running:
    print("")
    print("1) triangle  2) one row  3) one entry  4) floats  5) odd entries  6) quit")
    choice = plain(input("choice> "))
    if choice == "1":
        show_triangle()
    elif choice == "2":
        one_row()
    elif choice == "3":
        entry()
    elif choice == "4":
        floats()
    elif choice == "5":
        odd_pattern()
    elif choice == "6":
        running = False
    else:
        print("Pick a number from 1 to 6.")
print("Bye.")

triangle.eml

eml
# P124 Pascal's triangle - every row built from the one above by addition,
# so every entry is exact however many digits it has (the corpus cases
# pascals-triangle and pascal-row-exact). The checks tie a row to things
# computed another way: its mirror, its sum 2^n, the hockey stick to the
# next row, and the count of its odd entries. The multiplicative formula
# in floats is the comparison that goes wrong.

def next_row(row):
    [1] => out
    for k in [1:len(row) - 1]:
        out + [row[k - 1] + row[k]] => out
    return out + [1]

def row(n):
    [1] => r
    for i in [1:n]:
        next_row(r) => r
    return r

def rows(n):
    # rows 0 to n
    [[1]] => out
    [1] => r
    for i in [1:n]:
        next_row(r) => r
        out + [r] => out
    return out

def power_of_two(n):
    1 => p
    for i in [1:n]:
        p + p => p
    return p

def ones(n):
    # the 1 bits of n
    0 => c
    n => m
    while m > 0:
        if m % 2 == 1:
            c + 1 => c
            m - 1 => m
        int(m / 2) => m
    return c

def checks(n):
    # [symmetric, sum is 2^n, hockey stick holds for every k, odd entries,
    #  2^(1 bits of n)]
    rows(n + 1) => rs
    rs[n] => r
    True => sym
    0 => total
    0 => odd
    for k in [0:n]:
        if r[k] != r[n - k]:
            False => sym
        total + r[k] => total
        if r[k] % 2 == 1:
            odd + 1 => odd
    True => stick
    for k in [0:n]:
        0 => s
        for i in [k:n]:
            s + rs[i][k] => s
        if s != rs[n + 1][k + 1]:
            False => stick
    return [sym, total == power_of_two(n), stick, odd, power_of_two(ones(n))]

def float_entry(n, k):
    # C(n, k) by the multiplicative formula, in floats
    1.0 => c
    for i in [1:k]:
        c * (n - i + 1) / i => c
    return c

def first_float_miss(limit):
    # [n, k, the float, the exact entry, the product before the division]
    # for the first entry the float formula gets wrong, rows 0 to limit
    [1] => r
    for n in [0:limit]:
        if n > 0:
            next_row(r) => r
        1.0 => c
        for k in [0:n]:
            if k > 0:
                c * (n - k + 1) / k => c
            if c != r[k]:
                return [n, k, c, r[k], r[k - 1] * (n - k + 1)]
    return []

def digits(x):
    return len(str(x))
Python projection (triangle.py)
def next_row(row):
    out = [1]
    for k in range(1, len(row)):
        out = out + [row[k - 1] + row[k]]
    return out + [1]

def row(n):
    r = [1]
    for i in range(1, n+1):
        r = next_row(r)
    return r

def rows(n):
    out = [[1]]
    r = [1]
    for i in range(1, n+1):
        r = next_row(r)
        out = out + [r]
    return out

def power_of_two(n):
    p = 1
    for i in range(1, n+1):
        p = p + p
    return p

def ones(n):
    c = 0
    m = n
    while m > 0:
        if m % 2 == 1:
            c = c + 1
            m = m - 1
        m = int(m / 2)
    return c

def checks(n):
    rs = rows(n + 1)
    r = rs[n]
    sym = True
    total = 0
    odd = 0
    for k in range(0, n+1):
        if r[k] != r[n - k]:
            sym = False
        total = total + r[k]
        if r[k] % 2 == 1:
            odd = odd + 1
    stick = True
    for k in range(0, n+1):
        s = 0
        for i in range(k, n+1):
            s = s + rs[i][k]
        if s != rs[n + 1][k + 1]:
            stick = False
    return [sym, total == power_of_two(n), stick, odd, power_of_two(ones(n))]

def float_entry(n, k):
    c = 1.0
    for i in range(1, k+1):
        c = c * (n - i + 1) / i
    return c

def first_float_miss(limit):
    r = [1]
    for n in range(0, limit+1):
        if n > 0:
            r = next_row(r)
        c = 1.0
        for k in range(0, n+1):
            if k > 0:
                c = c * (n - k + 1) / k
            if c != r[k]:
                return [n, k, c, r[k], r[k - 1] * (n - k + 1)]
    return []

def digits(x):
    return len(str(x))

Built on these corpus cases

ΣEML 2026

Efficient New Language — a high-density semantic overlay for humans and AI agents.

This site’s demos run on the real EML toolchain, in your browser.

© 2026 EveMissLab (一言諾科技有限公司) / Neo.K. All rights reserved.