agentlang-index · task easy
Fibonacci with memoization
001-fibonacci-memoized. Read a single non-negative integer `N` from standard input.
Prompt
This is the natural-language brief given to every model, verbatim. The harness prefixes a language-specific calling-convention block and suffixes a "return only the source code" instruction. Nothing else.
## Task: Fibonacci with memoization
Read a single non-negative integer `N` from standard input. Compute
`fib(N)` using **memoization** (cache previously computed values so
repeated subproblems are O(1)). Write `fib(N)` followed by a single
newline to standard output. Exit with status 0.
Definition:
- `fib(0) = 0`
- `fib(1) = 1`
- `fib(n) = fib(n-1) + fib(n-2)` for `n >= 2`
## Acceptance
- Stdin: one line containing the integer `N`.
- Stdout: the decimal digits of `fib(N)` followed by `\n`.
- Stderr: empty.
- Exit code: 0.
- The program must complete `fib(50)` within 5 seconds. (A non-memoized
recursive solution will not meet this budget.)
## Examples
| N | stdout |
| -- | ----------------- |
| 0 | `0\n` |
| 1 | `1\n` |
| 10 | `55\n` |
| 50 | `12586269025\n` | Acceptance
A task counts as passed only when every public and hidden test case agrees on these fields. No fuzzy matching, no "off by one trailing newline is fine."
| stdout (byte-exact, per case) | true |
|---|---|
| stderr (exact bytes) | "" |
| exit code | 0 |
| wall time max (ms) | 5000 |
| requires memoization | true |
| tags | computation, memoization, recursion |
Results
Each cell is one attempt. Pass means stdout matched byte-exact on every test case, stderr empty, exit zero. Hover a failure to see the captured first line of the diagnostic.
| Model | Zero | TypeScript | Rust | Go | Python |
|---|---|---|---|---|---|
| gpt-4o | compile | ✓ | ✓ | ✓ | ✓ |
| gpt-4o-mini | compile | ✓ | ✓ | ✓ | ✓ |
| gpt-5 | compile | ✓ | ✓ | ✓ | ✓ |
| opus | compile | ✓ | ✓ | ✓ | ✓ |
| sonnet | wrong output | ✓ | ✓ | ✓ | ✓ |
Failure excerpts
5 of 25 attempts failed. Each card is one attempt, with the captured first line of the diagnostic.
-
ref.zero:1:1 IMP001: unknown package-local import 'std' -
ref.zero:4:1 PAR100: expected '{' before block -
ref.zero:1:1 IMP001: unknown package-local import 'std' -
ref.zero:1:13 PAR100: unexpected character '@' -
(no diagnostic captured)
Reference implementations
The hand-written reference each language ships with. Every reference passes the same public and hidden test suite under the pinned toolchain before any model touches the task.
Click a language to expand
Zero n/a
No reference implementation in this language.
TypeScript 30 lines
// Fibonacci with memoization, TypeScript reference.
// Reads N from stdin, caches fib(i) in a Map, writes fib(N) + newline.
// BigInt sidesteps the 2^53 precision limit of JS number for large N.
// Annotations are kept minimal so the same source also runs under plain
// `node` (TS type stripping varies by runner — tsx/bun handle it, older
// nodes don't). The Map's value type is documented in the comment instead.
const chunks = [];
process.stdin.on("data", (c) => chunks.push(c));
process.stdin.on("end", () => {
const input = Buffer.concat(chunks).toString("utf8").trim();
const n = Number.parseInt(input, 10);
if (!Number.isFinite(n) || n < 0) {
process.stderr.write("N must be a non-negative integer\n");
process.exit(1);
}
// memo: Map<number, bigint>
const memo = new Map();
memo.set(0, 0n);
memo.set(1, 1n);
const fib = (k) => {
const cached = memo.get(k);
if (cached !== undefined) return cached;
const v = fib(k - 1) + fib(k - 2);
memo.set(k, v);
return v;
};
process.stdout.write(fib(n).toString() + "\n");
});
Rust 31 lines
// Fibonacci with memoization, Rust reference.
// Reads N from stdin, caches fib(i) in a HashMap<u32, u64>.
// u64 holds fib(N) for N up to 93 (fib(93) = 12200160415121876738).
use std::collections::HashMap;
use std::io::{self, Read, Write};
fn fib(k: u32, memo: &mut HashMap<u32, u64>) -> u64 {
if let Some(&v) = memo.get(&k) {
return v;
}
let v = fib(k - 1, memo) + fib(k - 2, memo);
memo.insert(k, v);
v
}
fn main() {
let mut input = String::new();
io::stdin().read_to_string(&mut input).expect("read stdin");
let n: u32 = input
.trim()
.parse()
.expect("N must be a non-negative integer");
let mut memo: HashMap<u32, u64> = HashMap::new();
memo.insert(0, 0);
memo.insert(1, 1);
let v = fib(n, &mut memo);
let stdout = io::stdout();
let mut out = stdout.lock();
write!(out, "{}\n", v).expect("write stdout");
}
Go 34 lines
// Fibonacci with memoization, Go reference.
// Reads N from stdin, caches fib(i) in a map[int]uint64.
// uint64 holds fib(N) for N up to 93.
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func fib(k int, memo map[int]uint64) uint64 {
if v, ok := memo[k]; ok {
return v
}
v := fib(k-1, memo) + fib(k-2, memo)
memo[k] = v
return v
}
func main() {
reader := bufio.NewReader(os.Stdin)
line, _ := reader.ReadString('\n')
n, err := strconv.Atoi(strings.TrimSpace(line))
if err != nil || n < 0 {
fmt.Fprintln(os.Stderr, "N must be a non-negative integer")
os.Exit(1)
}
memo := map[int]uint64{0: 0, 1: 1}
fmt.Print(fib(n, memo), "\n")
}
Python 28 lines
"""Fibonacci with memoization, Python reference.
Reads N from stdin, caches fib(i) in a dict. Python ints are arbitrary
precision so no overflow concerns regardless of N.
"""
import sys
def main() -> None:
n = int(sys.stdin.readline().strip())
if n < 0:
sys.stderr.write("N must be a non-negative integer\n")
sys.exit(1)
memo: dict[int, int] = {0: 0, 1: 1}
def fib(k: int) -> int:
if k in memo:
return memo[k]
v = fib(k - 1) + fib(k - 2)
memo[k] = v
return v
sys.stdout.write(f"{fib(n)}\n")
if __name__ == "__main__":
main()
Design notes
Algorithm, failure modes, cross-language parity, and where Zero needed a workaround. From corpus/001-fibonacci-memoized/notes.md.
001-fibonacci-memoized — notes
First non-trivial corpus task. Probes whether a model picks a memoized strategy when the spec mandates it (the 5-second budget kills naive double-recursion at N=50). Every reference is explicitly memoized.
Memo representations across the references
- TS:
Map<number, bigint>, recursive - Rust:
HashMap<u32, u64>, recursive - Go:
map[int]uint64, recursive - Python:
dict[int, int], recursive (Python ints are bignum) - Zero: two parallel
[64]u32arrays (memo_hi / memo_lo) treated as a u64 memo, iterative bottom-up
All five fit comfortably within the 5-second wall budget at N=50.
Zero 0.1.2 direct-backend adaptations
The Zero reference takes notable liberties from the cross-language norm,
all forced by what the direct ELF64 MVP backend (zero-c) supports today:
N comes from
argv[1], not stdin. The 0.1.2Worldcapability exposesWorld.outandWorld.errbut noWorld.in, so stdin is unreachable from a hosted-world program. Every other language reads stdin.verify.shroutes input accordingly.u64 memo is two
[N]u32arrays. The direct backend restricts fixed-array local element types toi32,u32, andu8, so a[N]u64is rejected. The references store the high and low 32 bits of each fib(i) in parallel arrays and reconstruct u64 values for the recurrence.All logic stays inside
pub fun main. The direct backend rejectsSpan<u8>andMutSpan<u8>as function parameter types in the single-filezero runpath, so the digit parser and decimal renderer could not be factored out as helper functions.std.parse.parseU32not used. It is gated behind a literal-text requirement on the direct backend; the Zero reference walks the digits manually.u64 division + cast is split across statements. The expression
(sum / 4294967296_u64) as u32triggers a compiler crash on this backend revision. Binding intermediate variables for the divmod results before casting works around it. Worth filing upstream once the corpus stabilises and we have a minimal repro.
Public vs hidden test split
- Public (
tests/public/case-00{1..4}.json): N=0, 1, 10, 50. Mirrors the four examples inprompt.mdso a model can self-check. - Hidden (
tests/hidden/case-001.json): N=15 → 610. Not in the prompt; used by the harness to confirm the solution generalises and isn't table-lookup hardcoded.
Each case carries both stdin and argv because the harness needs to
adapt per language (Zero uses argv, others use stdin).
Cost
| Model | Prompt tokens | Completion tokens | API ms |
|---|---|---|---|
| gpt-4o | 2,555 | 950 | 8,727 |
| gpt-4o-mini | 2,555 | 812 | 22,753 |
| gpt-5 | 2,550 | 15,625 | 197,822 |
| opus | 14 | 948 | 70,517 |
| sonnet | 12 | 720 | 85,796 |
Tokens and API ms are summed across the five languages this model attempted for this task.
Compare
Model deep-dives: gpt-4o · gpt-4o-mini · gpt-5 · opus · sonnet . Back to the leaderboard and methodology.