llm
Download
61 lines 2.2 KiBTomoModified 2026-08-30 raw
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
# pidigits, from The Computer Language Benchmarks Game
#
# A Tomo port of Mr Ledrug's streaming spigot (the gcc-1 reference). This is a
# pure big-integer benchmark: the reference uses GMP's mpz_t throughout, and
# Tomo's default `Int` is exactly that, a GMP-backed arbitrary-precision
# integer (small values stay tagged; big ones spill to bignum), so the port is
# a near-transliteration with no inline C.
#
# Design notes:
#   - acc/den/num/k are all `Int` (bignum). Only the digit counters (`i`, `n`)
#     and the column index are native `Int64`, since they never grow.
#   - Tomo's `//` is Euclidean integer division, but every operand here is
#     non-negative, so it matches the reference's truncating `mpz_tdiv_q`.
#   - Output is written as raw bytes through a `byte_writer` (like fasta): the
#     ten digits of a line go into a small stack buffer, then the "\t:<count>\n"
#     tail is appended, so there's no per-digit Text allocation. This matches
#     the reference's `putchar` + `printf("\t:%u\n", i)` format exactly.
#
# Usage: pidigits <n>   (n a multiple of 10, e.g. ./pidigits 10000)

func extract_digit(num:Int, acc:Int, den:Int, nth:Int -> Int)
    return (num*nth + acc) // den

func main(n:Int64)
    acc := Int(0)
    den := Int(1)
    num := Int(1)
    k := Int(0)

    emit := (/dev/stdout).byte_writer(append=yes)
    row := &[Byte(0) for _ in 10]  # ten digit bytes of the current line
    col := Int64(0)
    i := Int64(0)
    while i < n
        # next_term(++k)
        k += 1
        k2 := k*2 + 1
        acc = (acc + num*2) * k2
        den = den * k2
        num = num * k
        if num > acc
            continue
        d := extract_digit(num, acc, den, 3)
        if d != extract_digit(num, acc, den, 4)
            continue

        col += 1
        row[col] = Byte(48 + d)
        i += 1
        if col == 10
            emit(row[])!
            emit("\t:$i\n".utf8())!
            col = 0

        # eliminate_digit(d)
        acc = (acc - den*d) * 10
        num = num * 10

    # Flush any trailing partial line (empty when n is a multiple of 10) and
    # close the stream. The reference doesn't pad a partial final line.
    emit(row[].to(Int(col)), close=yes)!