Features

16
16 passed, 0 failed

Scenarios

627
627 passed, 0 failed

Steps

1653
1653 passed, 0 failed, 0 skipped

The Anzan language itself

48/48 scenarios passed · 0µs
Operator precedence and associativityoutline · 6passed
2 + 3 * 4, 14, # multiplicative over additivepassed2ms
WhenI calculate "2 + 3 * 4"2ms
Thenthe result is "14"99µs
2^3^2, 512, # ^ is right-associativepassed10ms
WhenI calculate "2^3^2"10ms
Thenthe result is "512"76µs
-2^2, -4, # unary minus binds looser than ^passed228µs
WhenI calculate "-2^2"191µs
Thenthe result is "-4"33µs
2^-2, 0.25, # the exponent may carry its own signpassed151µs
WhenI calculate "2^-2"122µs
Thenthe result is "0.25"26µs
[10, 2][0]^2, 100, # postfix indexing binds tighter than ^passed167µs
WhenI calculate "[10, 2][0]^2"140µs
Thenthe result is "100"24µs
√4 + 5, 7, # prefix √ is unary, not greedypassed362µs
WhenI calculate "√4 + 5"333µs
Thenthe result is "7"26µs
Number literalsoutline · 6passed
1_000 + 0, 1000passed325µs
WhenI calculate "1_000 + 0"269µs
Thenthe result is "1000"48µs
2.5e-3, 0.0025passed856µs
WhenI calculate "2.5e-3"792µs
Thenthe result is "0.0025"58µs
.5 + .5, 1passed190µs
WhenI calculate ".5 + .5"160µs
Thenthe result is "1"27µs
0xFF, 255passed468µs
WhenI calculate "0xFF"400µs
Thenthe result is "255"62µs
0b1010, 10passed148µs
WhenI calculate "0b1010"100µs
Thenthe result is "10"44µs
0xDEAD_BEEF, 3735928559passed161µs
WhenI calculate "0xDEAD_BEEF"129µs
Thenthe result is "3735928559"28µs
Pinned cell references evaluate like plain onesoutline · 3passed
$A:$1 * 2passed3ms
Givencell A:1 contains "21"220µs
WhenI calculate "$A:$1 * 2"3ms
Thenthe result is "42"62µs
$A:1 + A:1passed345µs
Givencell A:1 contains "21"162µs
WhenI calculate "$A:1 + A:1"150µs
Thenthe result is "42"27µs
A:$1 * 2passed238µs
Givencell A:1 contains "21"138µs
WhenI calculate "A:$1 * 2"71µs
Thenthe result is "42"24µs
A dangling $ is a loud lex erroroutline · 3passed
$passed103µs
WhenI calculate "$"64µs
Thenthe calculation fails mentioning "pins a cell reference"36µs
$xpassed72µs
WhenI calculate "$x"40µs
Thenthe calculation fails mentioning "pins a cell reference"30µs
2 + $ratepassed87µs
WhenI calculate "2 + $rate"56µs
Thenthe calculation fails mentioning "pins a cell reference"29µs
A comment-only line is a note, not an errorpassed103µs
WhenI calculate "# the calc below confirms our test"72µs
Thenthe result is "# the calc below confirms our test"28µs
A standalone note never touches anspassed216µs
WhenI calculate "21 * 2"72µs
AndI calculate "# just thinking out loud"31µs
AndI calculate "ans"85µs
Thenthe result is "42"23µs
A trailing comment is stripped before evaluationpassed107µs
WhenI calculate "5 + 3 # adds them"82µs
Thenthe result is "8"22µs
A hash inside a string is not a commentpassed110µs
WhenI calculate "len("a # b")"81µs
Thenthe result is "5"25µs
Malformed programmer literals fail loudlyoutline · 4passed
0xFG, malformed hexpassed89µs
WhenI calculate "0xFG"55µs
Thenthe calculation fails mentioning "malformed hex"32µs
0x1.5, malformed hexpassed79µs
WhenI calculate "0x1.5"45µs
Thenthe calculation fails mentioning "malformed hex"31µs
0x, needs digitspassed71µs
WhenI calculate "0x"40µs
Thenthe calculation fails mentioning "needs digits"29µs
0b12, malformed binarypassed73µs
WhenI calculate "0b12"42µs
Thenthe calculation fails mentioning "malformed binary"28µs
Implicit multiplication covers parens, names, and constantspassed198µs
WhenI calculate "x9 = 4"95µs
AndI calculate "(2)(3) + 2x9"75µs
Thenthe result is "14"24µs
Modulo is exactpassed111µs
WhenI calculate "mod(0.3, 0.1)"87µs
Thenthe result is "0"22µs
Percent literalsoutline · 5passed
3%, 0.03passed77µs
WhenI calculate "3%"51µs
Thenthe result is "0.03"23µs
1 * 3%, 0.03passed86µs
WhenI calculate "1 * 3%"60µs
Thenthe result is "0.03"23µs
100 + 5%, 100.05passed99µs
WhenI calculate "100 + 5%"71µs
Thenthe result is "100.05"25µs
50% * 2, 1passed82µs
WhenI calculate "50% * 2"58µs
Thenthe result is "1"22µs
(2 + 3)%, 0.05passed85µs
WhenI calculate "(2 + 3)%"61µs
Thenthe result is "0.05"22µs
A number can't directly follow another valueoutline · 3passed
3 4passed84µs
WhenI calculate "3 4"52µs
Thenthe calculation fails mentioning "operator"30µs
3 % 4passed83µs
WhenI calculate "3 % 4"52µs
Thenthe calculation fails mentioning "operator"29µs
(1) 2passed86µs
WhenI calculate "(1) 2"55µs
Thenthe calculation fails mentioning "operator"29µs
A string is not a conditionpassed146µs
WhenI calculate "if("a", 1, 2)"117µs
Thenthe calculation fails mentioning "number"26µs
Empty reductions yield identitiespassed156µs
WhenI calculate "∑_i=1^0(i) + ∏_i=1^0(i)"130µs
Thenthe result is "1"23µs
A reduction spanning too many terms is refusedpassed171µs
WhenI calculate "∑_i=1^200000(i)"123µs
Thenthe calculation fails mentioning "100,000"44µs
Reserved words refuse assignmentoutline · 3passed
ans = 5passed99µs
WhenI calculate "ans = 5"57µs
Thenthe calculation fails mentioning "cannot assign"39µs
sigma = 1passed102µs
WhenI calculate "sigma = 1"63µs
Thenthe calculation fails mentioning "cannot assign"37µs
true = 0passed94µs
WhenI calculate "true = 0"54µs
Thenthe calculation fails mentioning "cannot assign"38µs
Parameters shadow globals without clobbering thempassed421µs
WhenI calculate "shade = 10"63µs
AndI calculate "twice(shade) = shade * 2"163µs
AndI calculate "twice(3) + shade"153µs
Thenthe result is "16"37µs
Free variables resolve at call timepassed305µs
WhenI calculate "base = 10"71µs
AndI calculate "above(y) = base + y"74µs
AndI calculate "base = 100"71µs
AndI calculate "above(1)"60µs
Thenthe result is "101"23µs
Special forms ship their manualpassed120µs
WhenI calculate "man if"61µs
Thendocumentation is shown mentioning "taken branch"55µs
String escapes are honoredpassed94µs
WhenI calculate "len("a\tb")"68µs
Thenthe result is "3"23µs
The word data is still an ordinary namepassed178µs
WhenI calculate "data = 5"88µs
AndI calculate "data * 2"51µs
Thenthe result is "10"35µs
Compact named arguments versus cell referencespassed571µs
GivenI calculate "data Q { a: Number, age: Number }"151µs
WhenI calculate "Q(a: 1, age:36).age"213µs
Thenthe result is "36"37µs
WhenI calculate "sum(a:1)"81µs
Thenthe result is "0"44µs

Calculating in the log

25/25 scenarios passed · 0µs
Everyday calculations are exactoutline · 10passed
0.1 + 0.2, 0.3passed178µs
WhenI calculate "0.1 + 0.2"131µs
Thenthe result is "0.3"42µs
2(3 + 4), 14passed172µs
WhenI calculate "2(3 + 4)"124µs
Thenthe result is "14"45µs
2^10, 1024passed165µs
WhenI calculate "2^10"138µs
Thenthe result is "1024"25µs
∑(1, 2, 3), 6passed136µs
WhenI calculate "∑(1, 2, 3)"110µs
Thenthe result is "6"23µs
∑_i=1^10(i^2), 385passed146µs
WhenI calculate "∑_i=1^10(i^2)"120µs
Thenthe result is "385"23µs
pmt(0.05/12, 360, 200000), -1073.643246024277969656985158225109053609679713701passed350ms
WhenI calculate "pmt(0.05/12, 360, 200000)"350ms
Thenthe result is "-1073.643246024277969656985158225109053609679713701"142µs
margin(100, 80), 20passed255µs
WhenI calculate "margin(100, 80)"188µs
Thenthe result is "20"61µs
date(2026, 6, 6) - date(2026, 1, 1), 156passed246µs
WhenI calculate "date(2026, 6, 6) - date(2026, 1, 1)"186µs
Thenthe result is "156"55µs
if(2 > 1, 10, 20), 10passed165µs
WhenI calculate "if(2 > 1, 10, 20)"123µs
Thenthe result is "10"38µs
gcd(48, 36), 12passed146µs
WhenI calculate "gcd(48, 36)"106µs
Thenthe result is "12"36µs
A hundred dimes make exactly a dollar bagpassed250µs
WhenI calculate "∑_i=1^100(0.1)"210µs
Thenthe result is "10"35µs
The previous answer carries forwardpassed165µs
WhenI calculate "6 * 7"66µs
AndI calculate "ans + 8"64µs
Thenthe result is "50"30µs
Variables persist across calculationspassed177µs
WhenI calculate "rate2026 = 0.0825"73µs
AndI calculate "1200 * rate2026"66µs
Thenthe result is "99"34µs
A leading equals sign is toleratedpassed109µs
WhenI calculate "= 1 + 2"72µs
Thenthe result is "3"34µs
A failed calculation never clobbers the previous answerpassed239µs
WhenI calculate "6 * 7"75µs
AndI calculate "1 / 0"66µs
AndI calculate "ans + 0"60µs
Thenthe result is "42"33µs
Dividing by zero explains itselfpassed100µs
WhenI calculate "1 / 0"60µs
Thenthe calculation fails mentioning "division by zero"37µs
Typos are caught, not guessedpassed128µs
WhenI calculate "12 * rte"82µs
Thenthe calculation fails mentioning "unknown variable 'rte'"43µs
Comparisons answer 1 or 0outline · 7passed
2 < 3, 1passed96µs
WhenI calculate "2 < 3"64µs
Thenthe result is "1"29µs
3 < 2, 0passed89µs
WhenI calculate "3 < 2"57µs
Thenthe result is "0"29µs
3 > 2, 1passed135µs
WhenI calculate "3 > 2"92µs
Thenthe result is "1"39µs
2 <= 2, 1passed113µs
WhenI calculate "2 <= 2"74µs
Thenthe result is "1"35µs
2 >= 3, 0passed97µs
WhenI calculate "2 >= 3"64µs
Thenthe result is "0"29µs
2 == 2, 1passed133µs
WhenI calculate "2 == 2"89µs
Thenthe result is "1"39µs
2 != 2, 0passed120µs
WhenI calculate "2 != 2"80µs
Thenthe result is "0"35µs
Comparison chains are rejected, not misreadpassed135µs
WhenI calculate "1 < 2 < 3"84µs
Thenthe calculation fails mentioning "can't be chained"48µs

Data types — declared records with named construction

55/55 scenarios passed · 0µs
Declaring a type registers its constructorpassed382µs
WhenI calculate "data Person { name: String, age: Number, active: Boolean }"110µs
Thenthe result is "data Person { name: String, age: Number, active: Boolean }"37µs
WhenI calculate "Person(name: "Ada", age: 36, active: true)"148µs
Thenthe result is "Person(name: "Ada", age: 36, active: true)"79µs
Construction is named fields or one map — never positionalpassed599µs
GivenI calculate "data Pt { x: Number, y: Number }"88µs
WhenI calculate "Pt(y: 4, x: 3)"104µs
Thenthe result is "Pt(x: 3, y: 4)"42µs
WhenI calculate "m = {x: 3, y: 4}"80µs
AndI calculate "Pt(m)"63µs
Thenthe result is "Pt(x: 3, y: 4)"38µs
WhenI calculate "Pt(3, 4)"101µs
Thenthe calculation fails mentioning "takes named fields"70µs
Field types accept any casing and Boolean fields render true/falsepassed249µs
WhenI calculate "data Flag { on: boolean }"79µs
Thenthe result is "data Flag { on: Boolean }"36µs
WhenI calculate "Flag(on: 1 < 2)"91µs
Thenthe result is "Flag(on: true)"36µs
Fields read like map members, by dot or by keypassed741µs
GivenI calculate "data Pt { x: Number, y: Number }"77µs
AndI calculate "p = Pt(x: 3, y: 4)"90µs
WhenI calculate "sqrt(p.x^2 + p.y^2)"238µs
Thenthe result is "5"34µs
WhenI calculate "p["y"]"51µs
Thenthe result is "4"31µs
WhenI calculate "keys(p)"60µs
Thenthe result is "["x", "y"]"63µs
WhenI calculate "len(p)"56µs
Thenthe result is "2"32µs
Records collect into arrays and flow through higher-order functionspassed963µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"103µs
AndI calculate "team = [Person(name: "Ada", age: 36, active: true), Person(name: "Grace", age: 30, active: false)]"166µs
WhenI calculate "map(x -> x.age, team)"111µs
Thenthe result is "[36, 30]"53µs
WhenI calculate "sum(map(x -> x.age, team))"134µs
Thenthe result is "66"39µs
WhenI calculate "filter(x -> x.active, team)"106µs
Thenthe result is "[Person(name: "Ada", age: 36, active: true)]"51µs
WhenI calculate "map(Person, [{name: "Bo", age: 1, active: true}])"135µs
Thenthe result is "[Person(name: "Bo", age: 1, active: true)]"48µs
Instances canonicalize to declaration order and compare deeplypassed604µs
GivenI calculate "data Pt { x: Number, y: Number }"144µs
WhenI calculate "Pt(y: 2, x: 1) == Pt(x: 1, y: 2)"196µs
Thenthe result is "1"52µs
WhenI calculate "Pt(x: 1, y: 2) == {x: 1, y: 2}"151µs
Thenthe result is "0"46µs
toJson is pretty by default, compact on request, honest about Booleanspassed616µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"107µs
AndI calculate "p = Person(name: "Ada", age: 36, active: true)"135µs
WhenI calculate "toJson(p)"68µs
Thenthe result is ""{\n \"name\": \"Ada\",\n \"age\": 36,\n \"active\": true\n}""45µs
WhenI calculate "toJson(p, Json.Compact)"79µs
Thenthe result is ""{\"name\":\"Ada\",\"age\":36,\"active\":true}""43µs
WhenI calculate "toJson([1, 2])"81µs
Thenthe result is ""[\n 1,\n 2\n]""45µs
fromJson parses JSON into values, exactlypassed878µs
WhenI calculate "fromJson("[1, 2, 3]")"96µs
Thenthe result is "[1, 2, 3]"44µs
WhenI calculate "fromJson("{\"name\": \"Ada\", \"age\": 36}").age"95µs
Thenthe result is "36"42µs
WhenI calculate "fromJson("0.30000000000000004") == 0.30000000000000004"129µs
Thenthe result is "1"36µs
WhenI calculate "fromJson("123456789012345678901234567890.5") * 2"115µs
Thenthe result is "246913578024691357802469135781"49µs
WhenI calculate "fromJson("true") + fromJson("false")"115µs
Thenthe result is "1"34µs
WhenI calculate "fromJson("\"\\u0041da\"")"70µs
Thenthe result is ""Ada""36µs
fromJson and a constructor re-type a serialized recordpassed590µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"98µs
AndI calculate "p = Person(name: "Ada", age: 36, active: true)"113µs
WhenI calculate "Person(fromJson(toJson(p))) == p"124µs
Thenthe result is "1"35µs
WhenI calculate "map(Person, fromJson(toJson([p, p])))[1].age"177µs
Thenthe result is "36"35µs
fromJson mistakes explain themselvesoutline · 5passed
fromJson("null"), has no Anzan valuepassed126µs
WhenI calculate "fromJson("null")"79µs
Thenthe calculation fails mentioning "has no Anzan value"44µs
fromJson("[1,"), unexpected endpassed132µs
WhenI calculate "fromJson("[1,")"73µs
Thenthe calculation fails mentioning "unexpected end"54µs
fromJson("[1] junk"), trailing contentpassed152µs
WhenI calculate "fromJson("[1] junk")"102µs
Thenthe calculation fails mentioning "trailing content"47µs
fromJson("{\"a\":1,\"a\":2}"), duplicate keypassed125µs
WhenI calculate "fromJson("{\"a\":1,\"a\":2}")"81µs
Thenthe calculation fails mentioning "duplicate key"42µs
fromJson(5), wants JSON textpassed121µs
WhenI calculate "fromJson(5)"76µs
Thenthe calculation fails mentioning "wants JSON text"42µs
Json options are named constants, not magic flagspassed592µs
WhenI calculate "Json.Pretty"58µs
Thenthe result is ""pretty""32µs
WhenI calculate "toJson([1, 2], Json.Compact)"104µs
Thenthe result is ""[1,2]""31µs
WhenI calculate "toJson([1, 2], "compact")"87µs
Thenthe result is ""[1,2]""45µs
WhenI calculate "Json = 5"80µs
Thenthe calculation fails mentioning "cannot assign"45µs
WhenI calculate "man Json"56µs
Thendocumentation is shown mentioning "Formatting options"40µs
Construction mistakes explain themselvesoutline · 9passed
Person(name: "Ada", age: 36), missing 'active'passed271µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"102µs
WhenI calculate "Person(name: "Ada", age: 36)"110µs
Thenthe calculation fails mentioning "missing 'active'"51µs
Person(name: 7, age: 36, active: true), 'name' of Person is a Stringpassed290µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"111µs
WhenI calculate "Person(name: 7, age: 36, active: true)"130µs
Thenthe calculation fails mentioning "'name' of Person is a String"45µs
Person(name: "A", age: "x", active: true), 'age' of Person is a Numberpassed244µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"92µs
WhenI calculate "Person(name: "A", age: "x", active: true)"111µs
Thenthe calculation fails mentioning "'age' of Person is a Number"38µs
Person(name: "A", age: 36, active: 7), use true or falsepassed254µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"91µs
WhenI calculate "Person(name: "A", age: 36, active: 7)"116µs
Thenthe calculation fails mentioning "use true or false"42µs
Person(name: "A", age: 36, active: true, pet: 1), no field 'pet'passed264µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"89µs
WhenI calculate "Person(name: "A", age: 36, active: true, pet: 1)"118µs
Thenthe calculation fails mentioning "no field 'pet'"49µs
Person(name: "A", name: "B", age: 1, active: 1), duplicate fieldpassed253µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"99µs
WhenI calculate "Person(name: "A", name: "B", age: 1, active: 1)"106µs
Thenthe calculation fails mentioning "duplicate field"44µs
toJson(sqrt), can't serialize a functionpassed216µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"89µs
WhenI calculate "toJson(sqrt)"74µs
Thenthe calculation fails mentioning "can't serialize a function"46µs
toJson(1, "wat"), unknown toJson optionpassed220µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"94µs
WhenI calculate "toJson(1, "wat")"80µs
Thenthe calculation fails mentioning "unknown toJson option"41µs
toJson(1, true), Json.Pretty or Json.Compactpassed219µs
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"91µs
WhenI calculate "toJson(1, true)"87µs
Thenthe calculation fails mentioning "Json.Pretty or Json.Compact"37µs
Declaration mistakes explain themselvesoutline · 5passed
data person { a: Number }, capital letterpassed105µs
WhenI calculate "data person { a: Number }"61µs
Thenthe calculation fails mentioning "capital letter"41µs
data Bad { a: truthy }, declared data typepassed106µs
WhenI calculate "data Bad { a: truthy }"59µs
Thenthe calculation fails mentioning "declared data type"44µs
data Empty {}, at least one fieldpassed96µs
WhenI calculate "data Empty {}"51µs
Thenthe calculation fails mentioning "at least one field"42µs
data Dup { a: Number, A: Number }, duplicate fieldpassed119µs
WhenI calculate "data Dup { a: Number, A: Number }"75µs
Thenthe calculation fails mentioning "duplicate field"41µs
data Abs { a: Number }, built-inpassed106µs
WhenI calculate "data Abs { a: Number }"67µs
Thenthe calculation fails mentioning "built-in"37µs
Types and functions can't share a name, but redeclaring your own type workspassed643µs
GivenI calculate "f(x) = x + 1"91µs
WhenI calculate "data F { a: Number }"64µs
Thenthe calculation fails mentioning "already a function"37µs
WhenI calculate "data G { a: Number }"65µs
AndI calculate "g(x) = x"64µs
Thenthe calculation fails mentioning "is a data type"50µs
WhenI calculate "data G { a: Number, b: Number }"103µs
AndI calculate "G(a: 1, b: 2).b"113µs
Thenthe result is "2"40µs
A type documents itself through its trailing commentpassed221µs
WhenI calculate "data Invoice { total: Number, paid: Boolean } # one customer invoice"99µs
AndI calculate "man Invoice"71µs
Thendocumentation is shown mentioning "one customer invoice"46µs
toJson escapes strings and renders empty containerspassed288µs
WhenI calculate "toJson("a\tb")"61µs
Thenthe result is ""\"a\\tb\"""37µs
WhenI calculate "toJson([])"59µs
Thenthe result is ""[]""35µs
WhenI calculate "toJson({})"55µs
Thenthe result is ""{}""34µs
A constructor call works in tail position of a recursive functionpassed367µs
GivenI calculate "data Box { v: Number }"68µs
AndI calculate "wrap(n) = if(n <= 0, Box(v: n), wrap(n - 1))"128µs
WhenI calculate "wrap(5).v"132µs
Thenthe result is "0"34µs
The explicit formula marker rejects declarations in cellspassed154µs
Givencell A:1 contains "=data Pt { x: Number }"95µs
Thencell A:1 shows an error mentioning "drop the leading '='"56µs
A plain declaration in a cell is a sheet-scoped 𝑫 typepassed473µs
Givencell A:1 contains "data Pt { x: Number, y: Number }"132µs
Andcell B:1 contains "Pt(x: 3, y: 4).x"96µs
Thencell A:1 shows "𝑫 Pt"78µs
Andcell B:1 shows "3"58µs
WhenI calculate "data Pt { x: Number }"64µs
Thenthe calculation fails mentioning "defined in cell Sheet 1!A:1"38µs
Types and record variables survive save and reopenpassed1ms
GivenI calculate "data Person { name: String, age: Number, active: Boolean }"93µs
AndI calculate "p = Person(name: "Ada", age: 36, active: true)"117µs
Whenthe workbook is saved and reopened747µs
AndI calculate "p.age + Person(name: "B", age: 4, active: false).age"134µs
Thenthe result is "40"46µs
A typed parameter dispatches a function by argument typepassed421µs
GivenI calculate "kind(n: Number) = "number""87µs
AndI calculate "kind(s: String) = "string""92µs
WhenI calculate "kind(42)"97µs
Thenthe result is ""number""35µs
WhenI calculate "kind("hi")"69µs
Thenthe result is ""string""33µs
A function can be written for a data typepassed543µs
GivenI calculate "data Point { x: Number, y: Number }"83µs
AndI calculate "midpoint(a: Point, b: Point) = Point(x: (a.x + b.x) / 2, y: (a.y + b.y) / 2)"154µs
WhenI calculate "midpoint(Point(x: 0, y: 0), Point(x: 4, y: 10))"258µs
Thenthe result is "Point(x: 2, y: 5)"42µs
An operator can be overloaded for a data typepassed386µs
GivenI calculate "data Point { x: Number, y: Number }"76µs
AndI calculate "+(a: Point, b: Point) = Point(x: a.x + b.x, y: a.y + b.y)"109µs
WhenI calculate "Point(x: 1, y: 2) + Point(x: 10, y: 20)"146µs
Thenthe result is "Point(x: 11, y: 22)"49µs
An overloaded operator can mix a data type and a scalarpassed340µs
GivenI calculate "data Point { x: Number, y: Number }"78µs
AndI calculate "*(a: Point, s: Number) = Point(x: a.x * s, y: a.y * s)"104µs
WhenI calculate "Point(x: 1, y: 2) * 3"114µs
Thenthe result is "Point(x: 3, y: 6)"39µs
Built-in arithmetic is untouched by an overloadpassed411µs
GivenI calculate "data Point { x: Number, y: Number }"74µs
AndI calculate "+(a: Point, b: Point) = Point(x: a.x + b.x, y: a.y + b.y)"107µs
WhenI calculate "1 + 2"61µs
Thenthe result is "3"49µs
WhenI calculate ""Q" + 1"75µs
Thenthe result is ""Q1""36µs
An operator overload must involve a data typepassed171µs
WhenI calculate "+(a: Number, b: Number) = 5"106µs
Thenthe calculation fails mentioning "must involve a data type"58µs
Records compare equal by all of their statepassed568µs
GivenI calculate "data Point { x: Number, y: Number }"85µs
WhenI calculate "Point(x: 1, y: 2) == Point(x: 1, y: 2)"134µs
Thenthe result is "1"35µs
WhenI calculate "Point(x: 1, y: 2) == Point(x: 9, y: 9)"122µs
Thenthe result is "0"33µs
WhenI calculate "Point(x: 1, y: 2) != Point(x: 9, y: 9)"118µs
Thenthe result is "1"33µs
Operator overloads survive save and reopenpassed1ms
GivenI calculate "data Point { x: Number, y: Number }"85µs
AndI calculate "+(a: Point, b: Point) = Point(x: a.x + b.x, y: a.y + b.y)"115µs
AndI calculate "*(a: Point, s: Number) = Point(x: a.x * s, y: a.y * s)"101µs
Whenthe workbook is saved and reopened342µs
AndI calculate "(Point(x: 1, y: 1) + Point(x: 2, y: 3)).y"168µs
Thenthe result is "4"34µs
AndI calculate "(Point(x: 2, y: 3) * 2).x"116µs
Thenthe result is "4"33µs
A data type can have fields of another data typepassed566µs
GivenI calculate "data Point { x: Number, y: Number }"81µs
AndI calculate "data Line { a: Point, b: Point }"70µs
AndI calculate "l = Line(a: Point(x: 1, y: 2), b: Point(x: 3, y: 4))"143µs
WhenI calculate "l.b.y"54µs
Thenthe result is "4"33µs
WhenI calculate "l == Line(a: Point(x: 1, y: 2), b: Point(x: 3, y: 4))"144µs
Thenthe result is "1"33µs
A nested field rejects the wrong typepassed309µs
GivenI calculate "data Point { x: Number, y: Number }"78µs
AndI calculate "data Line { a: Point, b: Point }"68µs
WhenI calculate "Line(a: 5, b: Point(x: 3, y: 4))"117µs
Thenthe calculation fails mentioning "is a Point"41µs
Nested records survive save and reopenpassed896µs
GivenI calculate "data Point { x: Number, y: Number }"72µs
AndI calculate "data Line { a: Point, b: Point }"70µs
AndI calculate "seg = Line(a: Point(x: 1, y: 1), b: Point(x: 4, y: 5))"191µs
Whenthe workbook is saved and reopened412µs
AndI calculate "seg.b.x - seg.a.x"101µs
Thenthe result is "3"38µs
A field can be a list of scalarspassed397µs
GivenI calculate "data Tags { items: [String] }"86µs
WhenI calculate "Tags(items: ["a", "b", "c"])"112µs
Thenthe result is "Tags(items: ["a", "b", "c"])"46µs
WhenI calculate "len(Tags(items: ["a", "b"]).items)"105µs
Thenthe result is "2"39µs
A field can be a list of records, nested freelypassed603µs
GivenI calculate "data Point { x: Number, y: Number }"94µs
AndI calculate "data Path { points: [Point] }"72µs
AndI calculate "p = Path(points: [Point(x: 1, y: 2), Point(x: 3, y: 4)])"177µs
WhenI calculate "p.points[1].y"85µs
Thenthe result is "4"40µs
WhenI calculate "len(p.points)"91µs
Thenthe result is "2"33µs
A field can be a nested listpassed300µs
GivenI calculate "data Grid { rows: [[Number]] }"111µs
WhenI calculate "Grid(rows: [[1, 2], [3, 4]]).rows[1][0]"148µs
Thenthe result is "3"36µs
A field can be a string-keyed mappassed237µs
GivenI calculate "data Config { opts: {String: Number} }"82µs
WhenI calculate "Config(opts: {a: 1, b: 2}).opts.b"115µs
Thenthe result is "2"34µs
List and map fields validate their elementsoutline · 3passed
Tags(items: [1, 2]), is a Stringpassed325µs
GivenI calculate "data Tags { items: [String] }"92µs
AndI calculate "data Config { opts: {String: Number} }"78µs
WhenI calculate "Tags(items: [1, 2])"106µs
Thenthe calculation fails mentioning "is a String"42µs
Tags(items: "x"), is a [String]passed268µs
GivenI calculate "data Tags { items: [String] }"76µs
AndI calculate "data Config { opts: {String: Number} }"75µs
WhenI calculate "Tags(items: "x")"71µs
Thenthe calculation fails mentioning "is a [String]"40µs
Config(opts: {a: "x"}), is a Numberpassed282µs
GivenI calculate "data Tags { items: [String] }"76µs
AndI calculate "data Config { opts: {String: Number} }"81µs
WhenI calculate "Config(opts: {a: "x"})"81µs
Thenthe calculation fails mentioning "is a Number"40µs
List and map fields survive save and reopenpassed820µs
GivenI calculate "data Point { x: Number, y: Number }"72µs
AndI calculate "data Path { points: [Point] }"66µs
AndI calculate "route = Path(points: [Point(x: 1, y: 1), Point(x: 5, y: 9)])"160µs
Whenthe workbook is saved and reopened407µs
AndI calculate "route.points[1].x"73µs
Thenthe result is "5"33µs

Fixed-precision decimals are SQL-style money values

20/20 scenarios passed · 0µs
Fixed-precision decimal construction and arithmeticoutline · 12passed
Decimal(0.5), Decimal(0.5)passed417µs
WhenI calculate "Decimal(0.5)"374µs
Thenthe result is "Decimal(0.5)"39µs
Decimal(3.14159), Decimal(3.14159)passed436µs
WhenI calculate "Decimal(3.14159)"393µs
Thenthe result is "Decimal(3.14159)"40µs
Decimal(0.5, 2), Decimal(0.50, 2)passed456µs
WhenI calculate "Decimal(0.5, 2)"409µs
Thenthe result is "Decimal(0.50, 2)"43µs
Decimal(10.5, 5, 2), Decimal(10.50, 5, 2)passed172µs
WhenI calculate "Decimal(10.5, 5, 2)"124µs
Thenthe result is "Decimal(10.50, 5, 2)"45µs
Decimal(1.005, 5, 2), Decimal(1.00, 5, 2)passed144µs
WhenI calculate "Decimal(1.005, 5, 2)"99µs
Thenthe result is "Decimal(1.00, 5, 2)"42µs
Decimal(1.005, 5, 2, Rounding.HalfUp), Decimal(1.01, 5, 2, Rounding.HalfUp)passed167µs
WhenI calculate "Decimal(1.005, 5, 2, Rounding.HalfUp)"112µs
Thenthe result is "Decimal(1.01, 5, 2, Rounding.HalfUp)"51µs
Decimal(123, 5, 0), Decimal(123, 5, 0)passed154µs
WhenI calculate "Decimal(123, 5, 0)"103µs
Thenthe result is "Decimal(123, 5, 0)"47µs
Decimal(2.50, 5, 2) + Decimal(1.25, 5, 2), Decimal(3.75, 5, 2)passed207µs
WhenI calculate "Decimal(2.50, 5, 2) + Decimal(1.25, 5, 2)"156µs
Thenthe result is "Decimal(3.75, 5, 2)"46µs
Decimal(10.00, 5, 2) - Decimal(0.01, 5, 2), Decimal(9.99, 5, 2)passed195µs
WhenI calculate "Decimal(10.00, 5, 2) - Decimal(0.01, 5, 2)"151µs
Thenthe result is "Decimal(9.99, 5, 2)"41µs
Decimal(2.50, 5, 2) * Decimal(4, 5, 2), Decimal(10.00, 5, 2)passed170µs
WhenI calculate "Decimal(2.50, 5, 2) * Decimal(4, 5, 2)"124µs
Thenthe result is "Decimal(10.00, 5, 2)"42µs
Decimal(10, 5, 2) / Decimal(3, 5, 2), Decimal(3.33, 5, 2)passed228µs
WhenI calculate "Decimal(10, 5, 2) / Decimal(3, 5, 2)"184µs
Thenthe result is "Decimal(3.33, 5, 2)"40µs
Decimal(10.00, 5, 2) + 0.005, Decimal(10.00, 5, 2)passed160µs
WhenI calculate "Decimal(10.00, 5, 2) + 0.005"116µs
Thenthe result is "Decimal(10.00, 5, 2)"40µs
Decimal overflow and bad mixes are loud errorsoutline · 5passed
Decimal(12345, 4, 0), exceedspassed141µs
WhenI calculate "Decimal(12345, 4, 0)"97µs
Thenthe calculation fails mentioning "exceeds"41µs
Decimal(999.99, 5, 2) + Decimal(0.01, 5, 2), exceedspassed175µs
WhenI calculate "Decimal(999.99, 5, 2) + Decimal(0.01, 5, 2)"133µs
Thenthe calculation fails mentioning "exceeds"39µs
Decimal(1, 5, 2) + Decimal(1, 5, 2, Rounding.HalfUp), roundingpassed314µs
WhenI calculate "Decimal(1, 5, 2) + Decimal(1, 5, 2, Rounding.HalfUp)"270µs
Thenthe calculation fails mentioning "rounding"40µs
Decimal(5, 5, 2) + Int8(5), combinepassed255µs
WhenI calculate "Decimal(5, 5, 2) + Int8(5)"212µs
Thenthe calculation fails mentioning "combine"40µs
Decimal(1, 1001, 2), between 1 and 1000passed179µs
WhenI calculate "Decimal(1, 1001, 2)"124µs
Thenthe calculation fails mentioning "between 1 and 1000"51µs
A Decimal coerces to its number outside typed arithmeticoutline · 3passed
Decimal(10.50, 5, 2) == 10.5, 1passed264µs
WhenI calculate "Decimal(10.50, 5, 2) == 10.5"223µs
Thenthe result is "1"37µs
Decimal(2.50, 5, 2) < 3, 1passed141µs
WhenI calculate "Decimal(2.50, 5, 2) < 3"104µs
Thenthe result is "1"34µs
sum(Decimal(1.5, 5, 2), Decimal(2.5, 5, 2)), 4passed185µs
WhenI calculate "sum(Decimal(1.5, 5, 2), Decimal(2.5, 5, 2))"147µs
Thenthe result is "4"34µs

Error handling — try, iferror, ifpanic, and the Result type

30/30 scenarios passed · 0µs
try turns success and domain errors into a Resultoutline · 10passed
try(2 + 2), Ok(4)passed109µs
WhenI calculate "try(2 + 2)"71µs
Thenthe result is "Ok(4)"35µs
try(1 / 0), Err("division by zero")passed112µs
WhenI calculate "try(1 / 0)"74µs
Thenthe result is "Err("division by zero")"35µs
try("abc"[9]), Err("index 9 is out of range (string has 3 characters)")passed123µs
WhenI calculate "try("abc"[9])"77µs
Thenthe result is "Err("index 9 is out of range (string has 3 characters)")"43µs
try(fromJson("invalidJson")), Err("fromJson: unexpected character 'i' at character 1")passed121µs
WhenI calculate "try(fromJson("invalidJson"))"76µs
Thenthe result is "Err("fromJson: unexpected character 'i' at character 1")"42µs
Ok(4), Ok(4)passed125µs
WhenI calculate "Ok(4)"87µs
Thenthe result is "Ok(4)"35µs
Err("nope"), Err("nope")passed92µs
WhenI calculate "Err("nope")"56µs
Thenthe result is "Err("nope")"33µs
try(2 + 2) == Ok(4), 1passed135µs
WhenI calculate "try(2 + 2) == Ok(4)"98µs
Thenthe result is "1"34µs
Ok(4) == Ok(4), 1passed137µs
WhenI calculate "Ok(4) == Ok(4)"99µs
Thenthe result is "1"35µs
Ok(4) == Ok(5), 0passed145µs
WhenI calculate "Ok(4) == Ok(5)"92µs
Thenthe result is "0"48µs
Ok(4) == Err("x"), 0passed134µs
WhenI calculate "Ok(4) == Err("x")"95µs
Thenthe result is "0"35µs
Result combinators read and default a Resultoutline · 9passed
isOk(try(2 + 2)), 1passed134µs
WhenI calculate "isOk(try(2 + 2))"95µs
Thenthe result is "1"35µs
isError(try(1 / 0)), 1passed135µs
WhenI calculate "isError(try(1 / 0))"97µs
Thenthe result is "1"34µs
isOk(try(1 / 0)), 0passed125µs
WhenI calculate "isOk(try(1 / 0))"89µs
Thenthe result is "0"33µs
isError(try(2 + 2)), 0passed117µs
WhenI calculate "isError(try(2 + 2))"82µs
Thenthe result is "0"33µs
unwrap(try(2 + 2)), 4passed126µs
WhenI calculate "unwrap(try(2 + 2))"81µs
Thenthe result is "4"42µs
unwrapOr(try(1 / 0), -1), -1passed134µs
WhenI calculate "unwrapOr(try(1 / 0), -1)"97µs
Thenthe result is "-1"34µs
unwrapOr(try(2 + 2), -1), 4passed155µs
WhenI calculate "unwrapOr(try(2 + 2), -1)"98µs
Thenthe result is "4"52µs
unwrapErr(try(1 / 0)), "division by zero"passed150µs
WhenI calculate "unwrapErr(try(1 / 0))"104µs
Thenthe result is ""division by zero""42µs
if(isOk(try(9)), unwrap(try(9)), 0), 9passed152µs
WhenI calculate "if(isOk(try(9)), unwrap(try(9)), 0)"117µs
Thenthe result is "9"32µs
iferror recovers a domain error with a fallbackoutline · 3passed
iferror(1 / 0, 0), 0passed115µs
WhenI calculate "iferror(1 / 0, 0)"81µs
Thenthe result is "0"31µs
iferror(2 + 2, 0), 4passed109µs
WhenI calculate "iferror(2 + 2, 0)"79µs
Thenthe result is "4"28µs
iferror("x"[9], -1), -1passed130µs
WhenI calculate "iferror("x"[9], -1)"96µs
Thenthe result is "-1"31µs
iferror does not evaluate its fallback on successpassed106µs
WhenI calculate "iferror(42, 1 / 0)"74µs
Thenthe result is "42"29µs
iferror does not catch a panic (runaway guard)passed152µs
WhenI calculate "iferror(sigma_i=1^200000(i), -1)"108µs
Thenthe calculation fails mentioning "100,000 terms"41µs
try does not catch a panic eitherpassed148µs
WhenI calculate "try(sigma_i=1^200000(i))"93µs
Thenthe calculation fails mentioning "100,000 terms"48µs
ifpanic catches a panic and returns its fallbackpassed181µs
WhenI calculate "ifpanic(sigma_i=1^200000(i), -1)"140µs
Thenthe result is "-1"37µs
ifpanic does not catch a domain error (wrong tier)passed132µs
WhenI calculate "ifpanic(1 / 0, -1)"91µs
Thenthe calculation fails mentioning "division by zero"38µs
Result mistakes explain themselvesoutline · 3passed
unwrap(try(1 / 0)), division by zeropassed123µs
WhenI calculate "unwrap(try(1 / 0))"82µs
Thenthe calculation fails mentioning "division by zero"38µs
unwrap(5), Resultpassed104µs
WhenI calculate "unwrap(5)"61µs
Thenthe calculation fails mentioning "Result"40µs
unwrapErr(Ok(4)), Okpassed117µs
WhenI calculate "unwrapErr(Ok(4))"78µs
Thenthe calculation fails mentioning "Ok"36µs

Fixed-width integers are bounded and checked

15/15 scenarios passed · 0µs
Fixed-width construction and checked arithmeticoutline · 6passed
Int32(27374), Int32(27374)passed168µs
WhenI calculate "Int32(27374)"97µs
Thenthe result is "Int32(27374)"65µs
Int(27374, 32), Int32(27374)passed152µs
WhenI calculate "Int(27374, 32)"100µs
Thenthe result is "Int32(27374)"49µs
Int8(5) + Int8(3), Int8(8)passed153µs
WhenI calculate "Int8(5) + Int8(3)"106µs
Thenthe result is "Int8(8)"44µs
Int8(5) + 3, Int8(8)passed142µs
WhenI calculate "Int8(5) + 3"95µs
Thenthe result is "Int8(8)"44µs
Int(100, 8) + Int(100, 16), Int16(200)passed268µs
WhenI calculate "Int(100, 8) + Int(100, 16)"221µs
Thenthe result is "Int16(200)"44µs
Int8(2) ^ 3, Int8(8)passed157µs
WhenI calculate "Int8(2) ^ 3"110µs
Thenthe result is "Int8(8)"44µs
Overflow and bad mixes are loud errors, never wrapsoutline · 5passed
Int8(200), out of rangepassed152µs
WhenI calculate "Int8(200)"91µs
Thenthe calculation fails mentioning "out of range"54µs
Int8(100) + Int8(100), out of rangepassed201µs
WhenI calculate "Int8(100) + Int8(100)"152µs
Thenthe calculation fails mentioning "out of range"46µs
UInt8(0) - 1, out of rangepassed156µs
WhenI calculate "UInt8(0) - 1"110µs
Thenthe calculation fails mentioning "out of range"43µs
Int8(5) + UInt8(5), signed and unsignedpassed154µs
WhenI calculate "Int8(5) + UInt8(5)"109µs
Thenthe calculation fails mentioning "signed and unsigned"42µs
Int8(5) + 1.5, whole numberspassed144µs
WhenI calculate "Int8(5) + 1.5"96µs
Thenthe calculation fails mentioning "whole numbers"45µs
Programmer-mode bitwise preserves the fixed-width typeoutline · 4passed
UInt8(12) & UInt8(10), UInt8(8)passed260µs
Giventhe calculator is in programmer mode37µs
WhenI calculate "UInt8(12) & UInt8(10)"168µs
Thenthe result is "UInt8(8)"50µs
~UInt8(0), UInt8(255)passed176µs
Giventhe calculator is in programmer mode38µs
WhenI calculate "~UInt8(0)"88µs
Thenthe result is "UInt8(255)"45µs
~Int8(0), Int8(-1)passed228µs
Giventhe calculator is in programmer mode49µs
WhenI calculate "~Int8(0)"122µs
Thenthe result is "Int8(-1)"49µs
UInt8(1) << 4, UInt8(16)passed182µs
Giventhe calculator is in programmer mode36µs
WhenI calculate "UInt8(1) << 4"100µs
Thenthe result is "UInt8(16)"41µs

Number formats are presentation, never value

15/15 scenarios passed · 0µs
A formatted cell displays its value in costumeoutline · 13passed
1234567.5, number, 1,234,567.50passed276µs
Givencell B:1 contains "1234567.5"77µs
Andcell B:1 is formatted as "number"83µs
Thencell B:1 displays "1,234,567.50"111µs
1234.5, dollars, $1,234.50passed165µs
Givencell B:1 contains "1234.5"67µs
Andcell B:1 is formatted as "dollars"44µs
Thencell B:1 displays "$1,234.50"50µs
-1234.5, dollars, -$1,234.50passed165µs
Givencell B:1 contains "-1234.5"67µs
Andcell B:1 is formatted as "dollars"46µs
Thencell B:1 displays "-$1,234.50"47µs
-2, euros, -€2.00passed178µs
Givencell B:1 contains "-2"70µs
Andcell B:1 is formatted as "euros"43µs
Thencell B:1 displays "-€2.00"59µs
0.0825, percent, 8.25%passed192µs
Givencell B:1 contains "0.0825"88µs
Andcell B:1 is formatted as "percent"49µs
Thencell B:1 displays "8.25%"50µs
1, percent, 100.00%passed154µs
Givencell B:1 contains "1"61µs
Andcell B:1 is formatted as "percent"46µs
Thencell B:1 displays "100.00%"43µs
20610, a date, 2026-06-06passed156µs
Givencell B:1 contains "20610"62µs
Andcell B:1 is formatted as "a date"42µs
Thencell B:1 displays "2026-06-06"48µs
0, a date, 1970-01-01passed144µs
Givencell B:1 contains "0"52µs
Andcell B:1 is formatted as "a date"42µs
Thencell B:1 displays "1970-01-01"46µs
195, hex, 0xC3passed158µs
Givencell B:1 contains "195"58µs
Andcell B:1 is formatted as "hex"42µs
Thencell B:1 displays "0xC3"55µs
-255, hex, -0xFFpassed154µs
Givencell B:1 contains "-255"58µs
Andcell B:1 is formatted as "hex"41µs
Thencell B:1 displays "-0xFF"51µs
195, binary, 0b1100_0011passed234µs
Givencell B:1 contains "195"56µs
Andcell B:1 is formatted as "binary"90µs
Thencell B:1 displays "0b1100_0011"83µs
5, binary, 0b101passed182µs
Givencell B:1 contains "5"73µs
Andcell B:1 is formatted as "binary"49µs
Thencell B:1 displays "0b101"55µs
1.5, hex, 1.5passed215µs
Givencell B:1 contains "1.5"82µs
Andcell B:1 is formatted as "hex"66µs
Thencell B:1 displays "1.5"60µs
Formatting never touches the underlying mathpassed424µs
Givencell B:1 contains "0.0825"93µs
Andcell B:1 is formatted as "percent"83µs
Andcell B:2 contains "=B:1 * 200"113µs
Thencell B:1 displays "8.25%"52µs
Andcell B:2 shows "16.5"71µs
Hex format is display-only, like every formatpassed410µs
Givencell A:1 contains "=bitOr(0xC0, 0x03)"112µs
Andcell A:1 is formatted as "hex"44µs
Andcell A:2 contains "=A:1 + 1"69µs
Thencell A:1 displays "0xC3"126µs
Andcell A:2 shows "196"52µs

Defining your own functions

16/16 scenarios passed · 0µs
Define a function and use itpassed262µs
WhenI calculate "tax(x) = x * 1.0825 # TX sales tax"114µs
AndI calculate "tax(100)"87µs
Thenthe result is "108.25"56µs
Functions compose regardless of definition orderpassed349µs
WhenI calculate "g(x) = f(x) + 1"143µs
AndI calculate "f(x) = x * 2"87µs
AndI calculate "g(20)"81µs
Thenthe result is "41"32µs
Recursion workspassed234µs
WhenI calculate "fact(n) = if(n <= 1, 1, n * fact(n - 1))"125µs
AndI calculate "fact(10)"74µs
Thenthe result is "3628800"31µs
Lambdas are valuespassed160µs
WhenI calculate "map(x -> x * 2, [1, 2, 3])"115µs
Thenthe result is "[2, 4, 6]"42µs
Structures carry datapassed228µs
WhenI calculate "people = [{name: "Ada", age: 36}, {name: "Bob", age: 32}]"117µs
AndI calculate "people[0].age"73µs
Thenthe result is "36"34µs
Machin's 1706 formula recovers pipassed2ms
WhenI calculate "arctanInv(x, n) = ∑_k=0^(n)((-1)^k / ((2k + 1) * x^(2k + 1)))"157µs
AndI calculate "16 * arctanInv(5, 40) - 4 * arctanInv(239, 15) - pi"2ms
Thenthe result is within "1e-45" of zero53µs
Comments are for humans and ignored by the mathpassed101µs
WhenI calculate "6 * 7 # the answer"65µs
Thenthe result is "42"33µs
A trailing comment becomes the function's documentationpassed195µs
WhenI calculate "tax(x) = x * 1.0825 # TX sales tax"89µs
AndI calculate "man tax"64µs
Thendocumentation is shown mentioning "TX sales tax"38µs
Built-in functions ship their manualpassed89µs
WhenI calculate "man pmt"46µs
Thendocumentation is shown mentioning "payment"40µs
Only the taken branch of if() runspassed121µs
WhenI calculate "if(1, 2, 1/0)"89µs
Thenthe result is "2"30µs
Deep recursion is bounded by memory, not a counterpassed34ms
WhenI calculate "countdown(n) = if(n <= 0, 0, countdown(n - 1) + 1)"118µs
AndI calculate "countdown(2000)"34ms
Thenthe result is "2000"80µs
Tail-recursive functions run at constant stack — any depthpassed4.54s
WhenI calculate "sumTo(n, acc) = if(n <= 0, acc, sumTo(n - 1, acc + n))"191µs
AndI calculate "sumTo(500000, 0)"4.54s
Thenthe result is "125000250000"101µs
Forgetting a base case fails politely, with a hintpassed338ms
WhenI calculate "F(n) = F(n - 1) + F(n - 2)"216µs
AndI calculate "f(3)"338ms
Thenthe calculation fails mentioning "base case"120µs
Runaway recursion is cut off cleanly, not a crashpassed7.15s
WhenI calculate "loop(n) = loop(n + 1)"201µs
AndI calculate "loop(1)"7.15s
Thenthe calculation fails mentioning "nested too deeply"181µs
Built-in names are protectedpassed324µs
WhenI calculate "abs(x) = x"265µs
Thenthe calculation fails mentioning "built-in"53µs
Function calls are case-insensitivepassed439µs
WhenI calculate "MIN(1, 2) + Sqrt(16)"391µs
Thenthe result is "5"43µs

The expanded function library

114/114 scenarios passed · 0µs
Exact combinatorics — BigInt keeps every digitoutline · 7passed
choose(5, 2), 10passed141µs
WhenI calculate "choose(5, 2)"102µs
Thenthe result is "10"35µs
choose(52, 5), 2598960passed116µs
WhenI calculate "choose(52, 5)"80µs
Thenthe result is "2598960"33µs
choose(100, 50), 100891344545564193334812497256passed258µs
WhenI calculate "choose(100, 50)"206µs
Thenthe result is "100891344545564193334812497256"48µs
choose(2, 5), 0passed155µs
WhenI calculate "choose(2, 5)"113µs
Thenthe result is "0"38µs
perm(5, 2), 20passed143µs
WhenI calculate "perm(5, 2)"102µs
Thenthe result is "20"37µs
perm(10, 3), 720passed124µs
WhenI calculate "perm(10, 3)"85µs
Thenthe result is "720"35µs
perm(10, 10), 3628800passed122µs
WhenI calculate "perm(10, 10)"84µs
Thenthe result is "3628800"36µs
Array plumbingoutline · 11passed
sort([3, 1, 2]), [1, 2, 3]passed215µs
WhenI calculate "sort([3, 1, 2])"160µs
Thenthe result is "[1, 2, 3]"50µs
sort(["pear", "fig", "kiwi"]), ["fig", "kiwi", "pear"]passed133µs
WhenI calculate "sort(["pear", "fig", "kiwi"])"87µs
Thenthe result is "["fig", "kiwi", "pear"]"43µs
unique([3, 1, 3, 2, 1]), [3, 1, 2]passed165µs
WhenI calculate "unique([3, 1, 3, 2, 1])"120µs
Thenthe result is "[3, 1, 2]"42µs
reverse([1, 2, 3]), [3, 2, 1]passed132µs
WhenI calculate "reverse([1, 2, 3])"90µs
Thenthe result is "[3, 2, 1]"39µs
reverse("abc"), "cba"passed117µs
WhenI calculate "reverse("abc")"76µs
Thenthe result is ""cba""37µs
seq(1, 5), [1, 2, 3, 4, 5]passed124µs
WhenI calculate "seq(1, 5)"81µs
Thenthe result is "[1, 2, 3, 4, 5]"41µs
seq(10, 0, -2), [10, 8, 6, 4, 2, 0]passed156µs
WhenI calculate "seq(10, 0, -2)"108µs
Thenthe result is "[10, 8, 6, 4, 2, 0]"44µs
sum(map(x -> x^2, seq(1, 10))), 385passed255µs
WhenI calculate "sum(map(x -> x^2, seq(1, 10)))"214µs
Thenthe result is "385"38µs
list(1, 2, 3), [1, 2, 3]passed155µs
WhenI calculate "list(1, 2, 3)"109µs
Thenthe result is "[1, 2, 3]"42µs
sumproduct([2, 3], [10, 100]), 320passed235µs
WhenI calculate "sumproduct([2, 3], [10, 100])"194µs
Thenthe result is "320"37µs
sumproduct(1, 2, 3, 4, 5, 6), 32passed219µs
WhenI calculate "sumproduct(1, 2, 3, 4, 5, 6)"168µs
Thenthe result is "32"44µs
list() turns a range into an array — higher-order functions over cellspassed739µs
Giventhe sheet contains:280µs
WhenI calculate "sum(filter(x -> x > 10, list(A:1..A:4)))"252µs
Thenthe result is "42"40µs
WhenI calculate "map(x -> x * 2, list(A:1..A:2))"114µs
Thenthe result is "[10, 24]"42µs
Statistics depth (sample conventions, full precision)outline · 11passed
variance(2, 4, 4, 4, 5, 5, 7, 9), 4.5714285714285714285714285714285714285714285714286passed294µs
WhenI calculate "variance(2, 4, 4, 4, 5, 5, 7, 9)"217µs
Thenthe result is "4.5714285714285714285714285714285714285714285714286"73µs
mode(1, 2, 2, 3, 3, 3), 3passed178µs
WhenI calculate "mode(1, 2, 2, 3, 3, 3)"138µs
Thenthe result is "3"36µs
mode(4, 9, 4, 9), 4passed148µs
WhenI calculate "mode(4, 9, 4, 9)"109µs
Thenthe result is "4"36µs
percentile(15, 20, 35, 40, 50, 0.4), 29passed183µs
WhenI calculate "percentile(15, 20, 35, 40, 50, 0.4)"149µs
Thenthe result is "29"31µs
percentile(1, 2, 3, 4, 0.75), 3.25passed280µs
WhenI calculate "percentile(1, 2, 3, 4, 0.75)"191µs
Thenthe result is "3.25"81µs
percentile(1, 2, 3, 1), 3passed185µs
WhenI calculate "percentile(1, 2, 3, 1)"144µs
Thenthe result is "3"38µs
geomean(4, 9), 6passed278µs
WhenI calculate "geomean(4, 9)"237µs
Thenthe result is "6"37µs
correl(1, 2, 3, 2, 4, 6), 1passed440µs
WhenI calculate "correl(1, 2, 3, 2, 4, 6)"398µs
Thenthe result is "1"38µs
slope(3, 5, 7, 1, 2, 3), 2passed267µs
WhenI calculate "slope(3, 5, 7, 1, 2, 3)"228µs
Thenthe result is "2"35µs
intercept(3, 5, 7, 1, 2, 3), 1passed301µs
WhenI calculate "intercept(3, 5, 7, 1, 2, 3)"248µs
Thenthe result is "1"47µs
forecast(4, 3, 5, 7, 1, 2, 3), 9passed329µs
WhenI calculate "forecast(4, 3, 5, 7, 1, 2, 3)"288µs
Thenthe result is "9"37µs
Amortization and depreciationoutline · 10passed
round(ipmt(0.05/12, 1, 360, 200000), 10), -833.3333333333passed350ms
WhenI calculate "round(ipmt(0.05/12, 1, 360, 200000), 10)"350ms
Thenthe result is "-833.3333333333"76µs
round(ipmt(0.05/12, 360, 360, 200000), 10), -4.4549512283passed845ms
WhenI calculate "round(ipmt(0.05/12, 360, 360, 200000), 10)"845ms
Thenthe result is "-4.4549512283"80µs
round(cumipmt(0.05/12, 360, 200000, 1, 12), 2), -9932.99passed370ms
WhenI calculate "round(cumipmt(0.05/12, 360, 200000, 1, 12), 2)"370ms
Thenthe result is "-9932.99"73µs
round(cumprinc(0.05/12, 360, 200000, 1, 12), 2), -2950.73passed351ms
WhenI calculate "round(cumprinc(0.05/12, 360, 200000, 1, 12), 2)"351ms
Thenthe result is "-2950.73"75µs
ipmt(0.05/12, 7, 360, 200000) + ppmt(0.05/12, 7, 360, 200000) == pmt(0.05/12, 360, 200000), 1passed1.06s
WhenI calculate "ipmt(0.05/12, 7, 360, 200000) + ppmt(0.05/12, 7, 360, 200000) == pmt(0.05/12, 360, 200000)"1.06s
Thenthe result is "1"87µs
sln(30000, 7500, 10), 2250passed296µs
WhenI calculate "sln(30000, 7500, 10)"240µs
Thenthe result is "2250"50µs
round(syd(30000, 7500, 10, 1), 2), 4090.91passed262µs
WhenI calculate "round(syd(30000, 7500, 10, 1), 2)"217µs
Thenthe result is "4090.91"41µs
ddb(30000, 7500, 10, 1), 6000passed198µs
WhenI calculate "ddb(30000, 7500, 10, 1)"156µs
Thenthe result is "6000"38µs
ddb(30000, 7500, 10, 10), 0passed189µs
WhenI calculate "ddb(30000, 7500, 10, 10)"152µs
Thenthe result is "0"34µs
round(nominal(effectiveRate(0.06, 12), 12), 10), 0.06passed639µs
WhenI calculate "round(nominal(effectiveRate(0.06, 12), 12), 10)"593µs
Thenthe result is "0.06"41µs
Business days and calendar positionsoutline · 9passed
quarter(date(2026, 6, 6)), 2passed158µs
WhenI calculate "quarter(date(2026, 6, 6))"119µs
Thenthe result is "2"36µs
quarter(date(2026, 11, 1)), 4passed153µs
WhenI calculate "quarter(date(2026, 11, 1))"111µs
Thenthe result is "4"39µs
weeknum(date(2026, 1, 1)), 1passed141µs
WhenI calculate "weeknum(date(2026, 1, 1))"103µs
Thenthe result is "1"35µs
weeknum(date(2026, 1, 4)), 2passed154µs
WhenI calculate "weeknum(date(2026, 1, 4))"114µs
Thenthe result is "2"36µs
workday(date(2026, 6, 5), 1) == date(2026, 6, 8), 1passed196µs
WhenI calculate "workday(date(2026, 6, 5), 1) == date(2026, 6, 8)"157µs
Thenthe result is "1"35µs
workday(date(2026, 6, 8), -1) == date(2026, 6, 5), 1passed196µs
WhenI calculate "workday(date(2026, 6, 8), -1) == date(2026, 6, 5)"158µs
Thenthe result is "1"35µs
networkdays(date(2026, 6, 1), date(2026, 6, 30)), 22passed185µs
WhenI calculate "networkdays(date(2026, 6, 1), date(2026, 6, 30))"148µs
Thenthe result is "22"34µs
networkdays(date(2026, 6, 1), date(2026, 6, 30), date(2026, 6, 19)), 21passed256µs
WhenI calculate "networkdays(date(2026, 6, 1), date(2026, 6, 30), date(2026, 6, 19))"201µs
Thenthe result is "21"50µs
networkdays(date(2026, 6, 5), date(2026, 6, 1)), -5passed216µs
WhenI calculate "networkdays(date(2026, 6, 5), date(2026, 6, 1))"175µs
Thenthe result is "-5"37µs
Scientific completionsoutline · 9passed
deg(pi), 180passed171µs
WhenI calculate "deg(pi)"132µs
Thenthe result is "180"36µs
deg(pi / 4), 45passed190µs
WhenI calculate "deg(pi / 4)"156µs
Thenthe result is "45"31µs
sin(rad(90)), 1passed343µs
WhenI calculate "sin(rad(90))"294µs
Thenthe result is "1"44µs
sinh(0), 0passed134µs
WhenI calculate "sinh(0)"97µs
Thenthe result is "0"33µs
cosh(0), 1passed123µs
WhenI calculate "cosh(0)"85µs
Thenthe result is "1"35µs
tanh(0), 0passed122µs
WhenI calculate "tanh(0)"81µs
Thenthe result is "0"37µs
asinh(0), 0passed114µs
WhenI calculate "asinh(0)"78µs
Thenthe result is "0"34µs
acosh(1), 0passed133µs
WhenI calculate "acosh(1)"83µs
Thenthe result is "0"44µs
atanh(0), 0passed127µs
WhenI calculate "atanh(0)"82µs
Thenthe result is "0"42µs
atan2 knows its quadrantpassed434µs
WhenI calculate "atan2(1, 1) - pi/4"178µs
Thenthe result is within "1e-15" of zero56µs
WhenI calculate "atan2(-1, -1) + 3 * pi/4"146µs
Thenthe result is within "1e-15" of zero49µs
Programmer tools — exact at any widthoutline · 14passed
toBase(255, 16), "FF"passed185µs
WhenI calculate "toBase(255, 16)"143µs
Thenthe result is ""FF""39µs
toBase(10, 2), "1010"passed132µs
WhenI calculate "toBase(10, 2)"94µs
Thenthe result is ""1010""35µs
fromBase("ff", 16), 255passed150µs
WhenI calculate "fromBase("ff", 16)"112µs
Thenthe result is "255"35µs
fromBase("1010", 2), 10passed151µs
WhenI calculate "fromBase("1010", 2)"117µs
Thenthe result is "10"31µs
toBase(-255, 16), "-FF"passed130µs
WhenI calculate "toBase(-255, 16)"93µs
Thenthe result is ""-FF""34µs
fromBase("-ff", 16), -255passed135µs
WhenI calculate "fromBase("-ff", 16)"98µs
Thenthe result is "-255"34µs
fromBase(toBase(123456789012345678901234567890, 36), 36), 123456789012345678901234567890passed244µs
WhenI calculate "fromBase(toBase(123456789012345678901234567890, 36), 36)"196µs
Thenthe result is "123456789012345678901234567890"46µs
bitAnd(12, 10), 8passed141µs
WhenI calculate "bitAnd(12, 10)"104µs
Thenthe result is "8"33µs
bitOr(12, 10), 14passed128µs
WhenI calculate "bitOr(12, 10)"92µs
Thenthe result is "14"33µs
bitXor(12, 10), 6passed137µs
WhenI calculate "bitXor(12, 10)"100µs
Thenthe result is "6"34µs
bitShift(1, 100), 1.267650600228229401496703205376e+30passed175µs
WhenI calculate "bitShift(1, 100)"123µs
Thenthe result is "1.267650600228229401496703205376e+30"49µs
bitShift(256, -4), 16passed123µs
WhenI calculate "bitShift(256, -4)"88µs
Thenthe result is "16"33µs
bitAnd(0xFF, 0x0F), 15passed135µs
WhenI calculate "bitAnd(0xFF, 0x0F)"100µs
Thenthe result is "15"33µs
toBase(0b1111, 16), "F"passed154µs
WhenI calculate "toBase(0b1111, 16)"106µs
Thenthe result is ""F""42µs
solve() is goal seek in a formulapassed79ms
WhenI calculate "solve(x -> x^2, 2) - sqrt(2)"754µs
Thenthe result is within "1e-12" of zero72µs
WhenI calculate "solve(cos, 0, 1) - pi/2"477µs
Thenthe result is within "1e-12" of zero59µs
WhenI calculate "solve(x -> if(x < 1, -1, 1), 0) - 1"1ms
Thenthe result is within "1e-12" of zero53µs
WhenI calculate "solve(r -> fv(r, 120, -100), 20000, 0.01) * 12"76ms
Thenthe result is within "1e-9" of "0.0958092381724"116µs
Derived builtins equal their definitionsoutline · 16passed
avg(2, 4, 9) == sum(2, 4, 9) / count(2, 4, 9)passed312µs
WhenI calculate "avg(2, 4, 9) == sum(2, 4, 9) / count(2, 4, 9)"269µs
Thenthe result is "1"39µs
stdev(2, 4, 4, 7) == sqrt(variance(2, 4, 4, 7))passed546µs
WhenI calculate "stdev(2, 4, 4, 7) == sqrt(variance(2, 4, 4, 7))"502µs
Thenthe result is "1"39µs
variance(2, 4) == ((2 - 3)^2 + (4 - 3)^2) / 1passed305µs
WhenI calculate "variance(2, 4) == ((2 - 3)^2 + (4 - 3)^2) / 1"266µs
Thenthe result is "1"35µs
cbrt(27) == root(27, 3)passed168µs
WhenI calculate "cbrt(27) == root(27, 3)"135µs
Thenthe result is "1"30µs
geomean(2, 4, 8) == root(product(2, 4, 8), 3)passed241µs
WhenI calculate "geomean(2, 4, 8) == root(product(2, 4, 8), 3)"197µs
Thenthe result is "1"39µs
percent(8.25) == 8.25 / 100passed224µs
WhenI calculate "percent(8.25) == 8.25 / 100"184µs
Thenthe result is "1"36µs
deg(2) == 2 * 180 / pipassed176µs
WhenI calculate "deg(2) == 2 * 180 / pi"138µs
Thenthe result is "1"35µs
choose(10, 4) == fact(10) / (fact(4) * fact(6))passed228µs
WhenI calculate "choose(10, 4) == fact(10) / (fact(4) * fact(6))"189µs
Thenthe result is "1"35µs
perm(10, 4) == fact(10) / fact(6)passed204µs
WhenI calculate "perm(10, 4) == fact(10) / fact(6)"167µs
Thenthe result is "1"34µs
lcm(12, 18) == 12 * 18 / gcd(12, 18)passed200µs
WhenI calculate "lcm(12, 18) == 12 * 18 / gcd(12, 18)"163µs
Thenthe result is "1"34µs
median(4, 1, 3) == sort([4, 1, 3])[1]passed186µs
WhenI calculate "median(4, 1, 3) == sort([4, 1, 3])[1]"148µs
Thenthe result is "1"35µs
sumproduct([2, 3], [10, 100]) == 2 * 10 + 3 * 100passed193µs
WhenI calculate "sumproduct([2, 3], [10, 100]) == 2 * 10 + 3 * 100"155µs
Thenthe result is "1"35µs
npv(0.1, 300, 420) == 300 / 1.1 + 420 / 1.1^2passed242µs
WhenI calculate "npv(0.1, 300, 420) == 300 / 1.1 + 420 / 1.1^2"205µs
Thenthe result is "1"34µs
forecast(4, 3, 5, 7, 1, 2, 3) == intercept(3, 5, 7, 1, 2, 3) + slope(3, 5, 7, 1, 2, 3) * 4passed595µs
WhenI calculate "forecast(4, 3, 5, 7, 1, 2, 3) == intercept(3, 5, 7, 1, 2, 3) + slope(3, 5, 7, 1, 2, 3) * 4"557µs
Thenthe result is "1"35µs
quarter(date(2026, 11, 1)) == trunc((month(date(2026, 11, 1)) - 1) / 3) + 1passed256µs
WhenI calculate "quarter(date(2026, 11, 1)) == trunc((month(date(2026, 11, 1)) - 1) / 3) + 1"217µs
Thenthe result is "1"35µs
bitShift(5, 3) == 5 * 2^3passed172µs
WhenI calculate "bitShift(5, 3) == 5 * 2^3"137µs
Thenthe result is "1"32µs
The new functions explain their mistakesoutline · 24passed
choose(-1, 2), non-negativepassed191µs
WhenI calculate "choose(-1, 2)"134µs
Thenthe calculation fails mentioning "non-negative"53µs
sort([1, "a"]), all numbers or all stringspassed158µs
WhenI calculate "sort([1, "a"])"92µs
Thenthe calculation fails mentioning "all numbers or all strings"61µs
seq(1, 10, 0), can't be 0passed188µs
WhenI calculate "seq(1, 10, 0)"138µs
Thenthe calculation fails mentioning "can't be 0"46µs
mode(1, 2, 3), no value repeatspassed147µs
WhenI calculate "mode(1, 2, 3)"102µs
Thenthe calculation fails mentioning "no value repeats"43µs
percentile(1, 2, 3, 1.5), between 0 and 1passed164µs
WhenI calculate "percentile(1, 2, 3, 1.5)"119µs
Thenthe calculation fails mentioning "between 0 and 1"42µs
geomean(4, -9), positivepassed151µs
WhenI calculate "geomean(4, -9)"106µs
Thenthe calculation fails mentioning "positive"41µs
correl(1, 2, 3, 4, 5), equal-lengthpassed158µs
WhenI calculate "correl(1, 2, 3, 4, 5)"114µs
Thenthe calculation fails mentioning "equal-length"40µs
ipmt(0.05, 0, 12, 1000), 1 ≤ per ≤ nperpassed189µs
WhenI calculate "ipmt(0.05, 0, 12, 1000)"132µs
Thenthe calculation fails mentioning "1 ≤ per ≤ nper"53µs
syd(30000, 7500, 10, 11), 1 ≤ per ≤ lifepassed172µs
WhenI calculate "syd(30000, 7500, 10, 11)"119µs
Thenthe calculation fails mentioning "1 ≤ per ≤ life"49µs
toBase(1.5, 16), integerpassed146µs
WhenI calculate "toBase(1.5, 16)"103µs
Thenthe calculation fails mentioning "integer"41µs
fromBase("xyz", 16), not a base-16passed130µs
WhenI calculate "fromBase("xyz", 16)"88µs
Thenthe calculation fails mentioning "not a base-16"40µs
bitAnd(-1, 2), non-negativepassed153µs
WhenI calculate "bitAnd(-1, 2)"109µs
Thenthe calculation fails mentioning "non-negative"41µs
solve(x -> x^2 + 1, 0), did not convergepassed765µs
WhenI calculate "solve(x -> x^2 + 1, 0)"720µs
Thenthe calculation fails mentioning "did not converge"42µs
ipmt(0.05, 1, 0, 1000), 1 ≤ per ≤ nperpassed165µs
WhenI calculate "ipmt(0.05, 1, 0, 1000)"113µs
Thenthe calculation fails mentioning "1 ≤ per ≤ nper"49µs
cumipmt(0.05/12, 12, 1000, 5, 2), 1 ≤ start ≤ endpassed203µs
WhenI calculate "cumipmt(0.05/12, 12, 1000, 5, 2)"152µs
Thenthe calculation fails mentioning "1 ≤ start ≤ end"48µs
nominal(-2, 12), above -100%passed135µs
WhenI calculate "nominal(-2, 12)"91µs
Thenthe calculation fails mentioning "above -100%"41µs
ddb(30000, 7500, 10, 11), 1 ≤ per ≤ lifepassed160µs
WhenI calculate "ddb(30000, 7500, 10, 11)"109µs
Thenthe calculation fails mentioning "1 ≤ per ≤ life"48µs
sln(1, 1, 0), can't be 0passed131µs
WhenI calculate "sln(1, 1, 0)"85µs
Thenthe calculation fails mentioning "can't be 0"44µs
toBase(255, 50), 2–36passed131µs
WhenI calculate "toBase(255, 50)"81µs
Thenthe calculation fails mentioning "2–36"46µs
fromBase("", 16), at least one digitpassed130µs
WhenI calculate "fromBase("", 16)"85µs
Thenthe calculation fails mentioning "at least one digit"41µs
bitShift(1, 1.5), integerpassed137µs
WhenI calculate "bitShift(1, 1.5)"93µs
Thenthe calculation fails mentioning "integer"41µs
seq(1, 1000000), 100,000passed32ms
WhenI calculate "seq(1, 1000000)"32ms
Thenthe calculation fails mentioning "100,000"93µs
workday(date(2026, 1, 1), 200001), too manypassed248µs
WhenI calculate "workday(date(2026, 1, 1), 200001)"199µs
Thenthe calculation fails mentioning "too many"44µs
networkdays(date(1, 1, 1), date(9999, 1, 1)), too manypassed194µs
WhenI calculate "networkdays(date(1, 1, 1), date(9999, 1, 1))"150µs
Thenthe calculation fails mentioning "too many"41µs

The mathematics a user can reach

108/108 scenarios passed · 0µs
Core arithmetic and algebraoutline · 28passed
1 + 2 * 3, 7passed119µs
WhenI calculate "1 + 2 * 3"81µs
Thenthe result is "7"35µs
(1 + 2) * 3, 9passed160µs
WhenI calculate "(1 + 2) * 3"117µs
Thenthe result is "9"38µs
10 / 4, 2.5passed149µs
WhenI calculate "10 / 4"108µs
Thenthe result is "2.5"38µs
mod(7, 3), 1passed118µs
WhenI calculate "mod(7, 3)"81µs
Thenthe result is "1"34µs
-2^2, -4passed135µs
WhenI calculate "-2^2"89µs
Thenthe result is "-4"42µs
2^-1, 0.5passed190µs
WhenI calculate "2^-1"142µs
Thenthe result is "0.5"43µs
abs(-5), 5passed126µs
WhenI calculate "abs(-5)"85µs
Thenthe result is "5"37µs
min(3, 1, 2), 1passed134µs
WhenI calculate "min(3, 1, 2)"95µs
Thenthe result is "1"35µs
max(3, 1, 2), 3passed141µs
WhenI calculate "max(3, 1, 2)"104µs
Thenthe result is "3"33µs
floor(2.7), 2passed118µs
WhenI calculate "floor(2.7)"81µs
Thenthe result is "2"34µs
floor(-1.5), -2passed101µs
WhenI calculate "floor(-1.5)"70µs
Thenthe result is "-2"28µs
ceil(2.1), 3passed154µs
WhenI calculate "ceil(2.1)"107µs
Thenthe result is "3"43µs
ceil(-1.5), -1passed127µs
WhenI calculate "ceil(-1.5)"86µs
Thenthe result is "-1"36µs
trunc(-2.7), -2passed112µs
WhenI calculate "trunc(-2.7)"75µs
Thenthe result is "-2"35µs
round(2.345, 2), 2.34passed136µs
WhenI calculate "round(2.345, 2)"95µs
Thenthe result is "2.34"38µs
round(2.567, 2), 2.57passed127µs
WhenI calculate "round(2.567, 2)"85µs
Thenthe result is "2.57"38µs
round(2.5), 2passed150µs
WhenI calculate "round(2.5)"107µs
Thenthe result is "2"38µs
mod(7, 3), 1passed158µs
WhenI calculate "mod(7, 3)"93µs
Thenthe result is "1"61µs
fact(5), 120passed118µs
WhenI calculate "fact(5)"80µs
Thenthe result is "120"35µs
fact(20), 2432902008176640000passed123µs
WhenI calculate "fact(20)"81µs
Thenthe result is "2432902008176640000"40µs
gcd(12, 18), 6passed149µs
WhenI calculate "gcd(12, 18)"110µs
Thenthe result is "6"35µs
lcm(4, 6), 12passed120µs
WhenI calculate "lcm(4, 6)"83µs
Thenthe result is "12"35µs
percent(8.25), 0.0825passed154µs
WhenI calculate "percent(8.25)"116µs
Thenthe result is "0.0825"35µs
sqrt(144), 12passed247µs
WhenI calculate "sqrt(144)"209µs
Thenthe result is "12"35µs
cbrt(27), 3passed126µs
WhenI calculate "cbrt(27)"90µs
Thenthe result is "3"33µs
cbrt(-27), -3passed113µs
WhenI calculate "cbrt(-27)"76µs
Thenthe result is "-3"33µs
root(32, 5), 2passed133µs
WhenI calculate "root(32, 5)"97µs
Thenthe result is "2"33µs
pow(4, 0.5), 2passed129µs
WhenI calculate "pow(4, 0.5)"95µs
Thenthe result is "2"31µs
Mathematical symbols are first-classoutline · 11passed
√16, 4passed307µs
WhenI calculate "√16"262µs
Thenthe result is "4"40µs
√(2 + 2), 2passed284µs
WhenI calculate "√(2 + 2)"238µs
Thenthe result is "2"40µs
√2^2, 2passed281µs
WhenI calculate "√2^2"236µs
Thenthe result is "2"41µs
6 × 7 ÷ 2, 21passed177µs
WhenI calculate "6 × 7 ÷ 2"128µs
Thenthe result is "21"45µs
6 ÷ 2 − 1, 2passed168µs
WhenI calculate "6 ÷ 2 − 1"122µs
Thenthe result is "2"41µs
3 · 4, 12passed109µs
WhenI calculate "3 · 4"73µs
Thenthe result is "12"34µs
π − pi, 0passed124µs
WhenI calculate "π − pi"88µs
Thenthe result is "0"33µs
τ ÷ π, 2passed191µs
WhenI calculate "τ ÷ π"154µs
Thenthe result is "2"33µs
pi, 3.14159265358979323846264338327950288419716939937510582097494passed130µs
WhenI calculate "pi"59µs
Thenthe result is "3.14159265358979323846264338327950288419716939937510582097494"67µs
3 ≠ 2, 1passed154µs
WhenI calculate "3 ≠ 2"105µs
Thenthe result is "1"43µs
2 ≤ 2, 1passed121µs
WhenI calculate "2 ≤ 2"81µs
Thenthe result is "1"36µs
Constants are protectedpassed114µs
WhenI calculate "π = 3"64µs
Thenthe calculation fails mentioning "cannot assign to 'π'"47µs
Trigonometry (radians)outline · 6passed
sin(pi / 2), 1passed179µs
WhenI calculate "sin(pi / 2)"141µs
Thenthe result is "1"34µs
cos(pi), -1passed148µs
WhenI calculate "cos(pi)"109µs
Thenthe result is "-1"35µs
tan(pi / 4), 0.9999999999999999passed167µs
WhenI calculate "tan(pi / 4)"124µs
Thenthe result is "0.9999999999999999"40µs
asin(1) * 2, 3.1415926535897932passed157µs
WhenI calculate "asin(1) * 2"113µs
Thenthe result is "3.1415926535897932"41µs
acos(0) * 2, 3.1415926535897932passed138µs
WhenI calculate "acos(0) * 2"94µs
Thenthe result is "3.1415926535897932"41µs
atan(1) * 4, 3.1415926535897932passed148µs
WhenI calculate "atan(1) * 4"103µs
Thenthe result is "3.1415926535897932"42µs
The degree postfix converts to radiansoutline · 3passed
sin(90°), 1passed158µs
WhenI calculate "sin(90°)"121µs
Thenthe result is "1"35µs
cos(180°), -1passed155µs
WhenI calculate "cos(180°)"117µs
Thenthe result is "-1"35µs
90° == pi / 2, 1passed138µs
WhenI calculate "90° == pi / 2"101µs
Thenthe result is "1"34µs
Exponentials and logarithmsoutline · 6passed
exp(0), 1passed183µs
WhenI calculate "exp(0)"102µs
Thenthe result is "1"75µs
ln(e), 1passed178µs
WhenI calculate "ln(e)"142µs
Thenthe result is "1"33µs
log10(1000), 3passed117µs
WhenI calculate "log10(1000)"80µs
Thenthe result is "3"34µs
log(2, 8), 3passed122µs
WhenI calculate "log(2, 8)"87µs
Thenthe result is "3"33µs
sin(0), 0passed114µs
WhenI calculate "sin(0)"78µs
Thenthe result is "0"33µs
cos(0), 1passed108µs
WhenI calculate "cos(0)"72µs
Thenthe result is "1"33µs
exp inverts ln to within the Double seampassed169µs
WhenI calculate "exp(ln(7))"104µs
Thenthe result is within "0.000000000000002" of "7"62µs
Statistics over lists, arrays, and rangesoutline · 8passed
avg(2, 4, 9), 5passed155µs
WhenI calculate "avg(2, 4, 9)"119µs
Thenthe result is "5"33µs
median(1, 9, 5), 5passed126µs
WhenI calculate "median(1, 9, 5)"90µs
Thenthe result is "5"34µs
median(1, 2, 3, 4), 2.5passed177µs
WhenI calculate "median(1, 2, 3, 4)"138µs
Thenthe result is "2.5"36µs
count(1, 2, 3), 3passed179µs
WhenI calculate "count(1, 2, 3)"135µs
Thenthe result is "3"40µs
product(2, 3, 4), 24passed130µs
WhenI calculate "product(2, 3, 4)"93µs
Thenthe result is "24"34µs
stdev(2, 4, 4, 4, 5, 5, 7, 9), 2.1380899352993950774764278470380281724320113187307passed370µs
WhenI calculate "stdev(2, 4, 4, 4, 5, 5, 7, 9)"306µs
Thenthe result is "2.1380899352993950774764278470380281724320113187307"60µs
avg([2, 4, 9]), 5passed168µs
WhenI calculate "avg([2, 4, 9])"130µs
Thenthe result is "5"35µs
stdev(1, 3) - sqrt(2), 0passed418µs
WhenI calculate "stdev(1, 3) - sqrt(2)"381µs
Thenthe result is "0"34µs
Products mirror summationpassed246µs
WhenI calculate "∏(2, 3, 4)"86µs
Thenthe result is "24"34µs
WhenI calculate "∏_i=1^5(i)"88µs
Thenthe result is "120"33µs
Euler's number from its factorial seriespassed3ms
WhenI calculate "∑_k=0^45(1 / fact(k)) - e"2ms
Thenthe result is within "1e-45" of zero95µs
Nicomachus — the sum of cubes is the square of the sumpassed459µs
WhenI calculate "reduce((a, b) -> a + b, map(x -> x^3, [1,2,3,4,5,6,7,8,9,10]), 0) == (∑_i=1^10(i))^2"417µs
Thenthe result is "1"37µs
Three roads to twenty factorial agree exactlypassed770µs
WhenI calculate "rec(n) = if(n <= 1, 1, n * rec(n - 1))"127µs
AndI calculate "∏_i=1^20(i) == fact(20)"133µs
Thenthe result is "1"35µs
WhenI calculate "rec(20) == fact(20)"430µs
Thenthe result is "1"38µs
Compound growth's product form equals its closed form, exactlypassed363µs
WhenI calculate "grow(r, n) = ∏_i=1^(n)(1 + r)"114µs
AndI calculate "grow(0.05, 30) == 1.05^30"211µs
Thenthe result is "1"33µs
A mortgage payment round-trips the principal to 30 decimal placespassed843ms
WhenI calculate "pv(0.05/12, 360, pmt(0.05/12, 360, 200000)) - 200000"843ms
Thenthe result is within "1e-30" of zero136µs
Finance agrees with Excel (independent cross-validation)outline · 14passed
pmt(0.05/12, 360, 200000), -1073.64, 0.01passed385ms
WhenI calculate "pmt(0.05/12, 360, 200000)"385ms
Thenthe result is within "0.01" of "-1073.64"191µs
pmt(0, 12, 1200), -100, 0.000001passed299µs
WhenI calculate "pmt(0, 12, 1200)"229µs
Thenthe result is within "0.000001" of "-100"65µs
fv(0.06/12, 120, -100), 16387.93, 0.01passed778µs
WhenI calculate "fv(0.06/12, 120, -100)"696µs
Thenthe result is within "0.01" of "16387.93"77µs
fv(0, 12, -100), 1200, 0.000001passed378µs
WhenI calculate "fv(0, 12, -100)"302µs
Thenthe result is within "0.000001" of "1200"70µs
pv(0.04/12, 60, -500), 27149.53, 0.01passed24ms
WhenI calculate "pv(0.04/12, 60, -500)"24ms
Thenthe result is within "0.01" of "27149.53"155µs
nper(0.05/12, -1073.64, 200000), 360, 0.01passed297µs
WhenI calculate "nper(0.05/12, -1073.64, 200000)"235µs
Thenthe result is within "0.01" of "360"58µs
nper(0, -100, 1200), 12, 0.000001passed279µs
WhenI calculate "nper(0, -100, 1200)"201µs
Thenthe result is within "0.000001" of "12"73µs
rate(360, -1073.64, 200000) * 12, 0.05, 0.0001passed296µs
WhenI calculate "rate(360, -1073.64, 200000) * 12"190µs
Thenthe result is within "0.0001" of "0.05"102µs
npv(0.1, 3000, 4200, 6800), 11307.29, 0.01passed281µs
WhenI calculate "npv(0.1, 3000, 4200, 6800)"196µs
Thenthe result is within "0.01" of "11307.29"80µs
irr(-70000, 12000, 15000, 18000, 21000, 26000), 0.0866, 0.0001passed578µs
WhenI calculate "irr(-70000, 12000, 15000, 18000, 21000, 26000)"515µs
Thenthe result is within "0.0001" of "0.0866"59µs
effectiveRate(0.06, 12), 0.061678, 0.000001passed208µs
WhenI calculate "effectiveRate(0.06, 12)"140µs
Thenthe result is within "0.000001" of "0.061678"65µs
markup(80, 25), 100, 0.000001passed173µs
WhenI calculate "markup(80, 25)"114µs
Thenthe result is within "0.000001" of "100"56µs
percentOf(30, 120), 25, 0.000001passed170µs
WhenI calculate "percentOf(30, 120)"113µs
Thenthe result is within "0.000001" of "25"54µs
percentChange(80, 100), 25, 0.000001passed211µs
WhenI calculate "percentChange(80, 100)"146µs
Thenthe result is within "0.000001" of "25"61µs
A mortgage's lifetime cost, built up across linespassed393ms
WhenI calculate "r = 0.05 / 12"96µs
AndI calculate "payment = pmt(r, 360, 200000)"393ms
AndI calculate "payment * 360"179µs
Thenthe result is within "0.01" of "-386511.57"91µs
IRR refuses an unsolvable streampassed190µs
WhenI calculate "irr(1000, 2000)"131µs
Thenthe calculation fails mentioning "both positive and negative"54µs
Finance (spreadsheet sign convention)outline · 6passed
fv(0.1, 2, -100), 210passed193µs
WhenI calculate "fv(0.1, 2, -100)"154µs
Thenthe result is "210"36µs
npv(0, 10, 20, 30), 60passed247µs
WhenI calculate "npv(0, 10, 20, 30)"209µs
Thenthe result is "60"35µs
npv(0.1, 110), 100passed191µs
WhenI calculate "npv(0.1, 110)"156µs
Thenthe result is "100"32µs
nper(0, -10, 100), 10passed156µs
WhenI calculate "nper(0, -10, 100)"118µs
Thenthe result is "10"34µs
irr(-100, 110), 0.1passed149µs
WhenI calculate "irr(-100, 110)"110µs
Thenthe result is "0.1"35µs
effectiveRate(0.12, 12), 0.126825030131969720661201passed199µs
WhenI calculate "effectiveRate(0.12, 12)"149µs
Thenthe result is "0.126825030131969720661201"47µs
Accounting shorthandsoutline · 4passed
margin(100, 80), 20passed156µs
WhenI calculate "margin(100, 80)"119µs
Thenthe result is "20"34µs
markup(80, 25), 100passed150µs
WhenI calculate "markup(80, 25)"113µs
Thenthe result is "100"34µs
percentOf(50, 200), 25passed169µs
WhenI calculate "percentOf(50, 200)"131µs
Thenthe result is "25"35µs
percentChange(100, 150), 50passed157µs
WhenI calculate "percentChange(100, 150)"121µs
Thenthe result is "50"33µs
Date arithmetic on exact day serialsoutline · 11passed
weekday(date(2026, 6, 6)), 6passed179µs
WhenI calculate "weekday(date(2026, 6, 6))"136µs
Thenthe result is "6"38µs
weekday(date(2026, 6, 8)), 1passed142µs
WhenI calculate "weekday(date(2026, 6, 8))"106µs
Thenthe result is "1"34µs
year(date(2026, 6, 6)), 2026passed135µs
WhenI calculate "year(date(2026, 6, 6))"98µs
Thenthe result is "2026"35µs
month(date(2026, 6, 6)), 6passed185µs
WhenI calculate "month(date(2026, 6, 6))"136µs
Thenthe result is "6"44µs
day(date(2026, 6, 6)), 6passed171µs
WhenI calculate "day(date(2026, 6, 6))"130µs
Thenthe result is "6"36µs
days(date(2026, 3, 1), date(2026, 2, 1)), 28passed190µs
WhenI calculate "days(date(2026, 3, 1), date(2026, 2, 1))"151µs
Thenthe result is "28"36µs
edate(date(2026, 1, 31), 1) == date(2026, 2, 28), 1passed234µs
WhenI calculate "edate(date(2026, 1, 31), 1) == date(2026, 2, 28)"190µs
Thenthe result is "1"39µs
eomonth(date(2024, 2, 1), 0) == date(2024, 2, 29), 1passed245µs
WhenI calculate "eomonth(date(2024, 2, 1), 0) == date(2024, 2, 29)"193µs
Thenthe result is "1"45µs
day(eomonth(date(1900, 2, 1), 0)), 28passed199µs
WhenI calculate "day(eomonth(date(1900, 2, 1), 0))"159µs
Thenthe result is "28"37µs
day(eomonth(date(2000, 2, 1), 0)), 29passed191µs
WhenI calculate "day(eomonth(date(2000, 2, 1), 0))"149µs
Thenthe result is "29"39µs
days(date(2001, 1, 1), date(2000, 1, 1)), 366passed189µs
WhenI calculate "days(date(2001, 1, 1), date(2000, 1, 1))"149µs
Thenthe result is "366"36µs
Logic composes with everythingpassed197µs
WhenI calculate "and(1 < 2, or(0, not(0)))"153µs
Thenthe result is "1"39µs

Input/display modes are dialects over one canonical language

61/61 scenarios passed · 0µs
Programmer mode reads glyphs as bitwise and modulooutline · 6passed
5 ^ 3, 6passed216µs
Giventhe calculator is in programmer mode35µs
WhenI calculate "5 ^ 3"141µs
Thenthe result is "6"35µs
12 & 10, 8passed155µs
Giventhe calculator is in programmer mode33µs
WhenI calculate "12 & 10"85µs
Thenthe result is "8"33µs
1 << 4, 16passed150µs
Giventhe calculator is in programmer mode36µs
WhenI calculate "1 << 4"76µs
Thenthe result is "16"33µs
8 >> 2, 2passed143µs
Giventhe calculator is in programmer mode32µs
WhenI calculate "8 >> 2"73µs
Thenthe result is "2"33µs
17 % 5, 2passed135µs
Giventhe calculator is in programmer mode34µs
WhenI calculate "17 % 5"64µs
Thenthe result is "2"32µs
pow(2, 10), 1024passed194µs
Giventhe calculator is in programmer mode45µs
WhenI calculate "pow(2, 10)"95µs
Thenthe result is "1024"48µs
Programmer mode reads pipe as bitwise ORpassed180µs
Giventhe calculator is in programmer mode36µs
WhenI calculate "12 | 3"104µs
Thenthe result is "15"35µs
Programmer-mode bitwise precedence follows Pythonpassed218µs
Giventhe calculator is in programmer mode35µs
WhenI calculate "1 & 1 == 1"128µs
Thenthe result is "1"47µs
Bitwise glyphs are Programmer-mode onlyoutline · 3passed
5 & 3passed126µs
WhenI calculate "5 & 3"75µs
Thenthe calculation fails mentioning "Programmer-mode operator"48µs
1 << 2passed105µs
WhenI calculate "1 << 2"64µs
Thenthe calculation fails mentioning "Programmer-mode operator"38µs
8 >> 1passed100µs
WhenI calculate "8 >> 1"59µs
Thenthe calculation fails mentioning "Programmer-mode operator"38µs
Scientific mode keeps the Normal arithmetic coreoutline · 3passed
2 ^ 3, 8passed172µs
Giventhe calculator is in scientific mode40µs
WhenI calculate "2 ^ 3"75µs
Thenthe result is "8"51µs
3%, 0.03passed141µs
Giventhe calculator is in scientific mode39µs
WhenI calculate "3%"62µs
Thenthe result is "0.03"36µs
50%, 0.5passed155µs
Giventhe calculator is in scientific mode49µs
WhenI calculate "50%"69µs
Thenthe result is "0.5"32µs
Scientific mode still rejects the Programmer-only glyphspassed153µs
Giventhe calculator is in scientific mode38µs
WhenI calculate "5 & 3"66µs
Thenthe calculation fails mentioning "Programmer-mode operator"44µs
Scientific mode echoes plain numbers in scientific notationoutline · 4passed
123456 * 2, 246912, 2.46912e5passed182µs
Giventhe calculator is in scientific mode34µs
WhenI calculate "123456 * 2"68µs
Thenthe result is "246912"35µs
Andthe log echoes "2.46912e5"41µs
5, 5, 5e0passed165µs
Giventhe calculator is in scientific mode37µs
WhenI calculate "5"56µs
Thenthe result is "5"34µs
Andthe log echoes "5e0"33µs
1 / 8, 0.125, 1.25e-1passed237µs
Giventhe calculator is in scientific mode50µs
WhenI calculate "1 / 8"114µs
Thenthe result is "0.125"34µs
Andthe log echoes "1.25e-1"32µs
-2500 * 2, -5000, -5e3passed176µs
Giventhe calculator is in scientific mode37µs
WhenI calculate "-2500 * 2"67µs
Thenthe result is "-5000"34µs
Andthe log echoes "-5e3"34µs
The engineering style snaps the exponent to a multiple of 3outline · 3passed
123456 * 2, 246.912e3passed183µs
Giventhe calculator is in scientific mode41µs
Andthe scientific style is "eng"34µs
WhenI calculate "123456 * 2"66µs
Thenthe log echoes "246.912e3"37µs
0.05, 50e-3passed166µs
Giventhe calculator is in scientific mode34µs
Andthe scientific style is "eng"33µs
WhenI calculate "0.05"60µs
Thenthe log echoes "50e-3"35µs
5, 5e0passed153µs
Giventhe calculator is in scientific mode35µs
Andthe scientific style is "eng"33µs
WhenI calculate "5"46µs
Thenthe log echoes "5e0"34µs
Money keeps its own display in scientific modepassed153µs
Giventhe calculator is in scientific mode28µs
WhenI calculate "$10 * 5%"75µs
Thenthe log echoes "$0.50"45µs
A grouped number keeps its grouping in scientific modepassed167µs
Giventhe calculator is in scientific mode38µs
WhenI calculate "138,561 * 9%"75µs
Thenthe log echoes "12,470.49"49µs
Degrees work in scientific modepassed247µs
Giventhe calculator is in scientific mode35µs
WhenI calculate "sin(90°)"141µs
Thenthe result is "1"34µs
Andthe log echoes "1e0"33µs
The finance mode is retired in favor of core currencypassed93µs
WhenI calculate ":mode finance"48µs
Thenthe calculation fails mentioning "currency now works"41µs
Currency carries through arithmeticoutline · 8passed
$10, Money(10, "USD"), $10.00passed132µs
WhenI calculate "$10"57µs
Thenthe result is "Money(10, "USD")"40µs
Andthe log echoes "$10.00"30µs
$10 * 5%, Money(0.5, "USD"), $0.50passed172µs
WhenI calculate "$10 * 5%"74µs
Thenthe result is "Money(0.5, "USD")"53µs
Andthe log echoes "$0.50"37µs
€10 * .4, Money(4, "EUR"), €4.00passed175µs
WhenI calculate "€10 * .4"96µs
Thenthe result is "Money(4, "EUR")"40µs
Andthe log echoes "€4.00"34µs
$10 + $5, Money(15, "USD"), $15.00passed171µs
WhenI calculate "$10 + $5"83µs
Thenthe result is "Money(15, "USD")"40µs
Andthe log echoes "$15.00"41µs
$10 - $2.50, Money(7.5, "USD"), $7.50passed162µs
WhenI calculate "$10 - $2.50"79µs
Thenthe result is "Money(7.5, "USD")"42µs
Andthe log echoes "$7.50"36µs
$100 / 4, Money(25, "USD"), $25.00passed181µs
WhenI calculate "$100 / 4"109µs
Thenthe result is "Money(25, "USD")"38µs
Andthe log echoes "$25.00"30µs
£1234.567, Money(1234.567, "GBP"), £1,234.57passed184µs
WhenI calculate "£1234.567"86µs
Thenthe result is "Money(1234.567, "GBP")"44µs
Andthe log echoes "£1,234.57"49µs
¥5000 * 2, Money(10000, "JPY"), ¥10,000.00passed189µs
WhenI calculate "¥5000 * 2"104µs
Thenthe result is "Money(10000, "JPY")"41µs
Andthe log echoes "¥10,000.00"40µs
The Money constructor works in normal modepassed190µs
WhenI calculate "Money(10, "USD")"108µs
Thenthe result is "Money(10, "USD")"40µs
Andthe log echoes "$10.00"36µs
An unknown currency code is refusedpassed219µs
WhenI calculate "Money(10, "XYZ")"169µs
Thenthe calculation fails mentioning "unknown currency"46µs
An unsupported currency glyph is refusedpassed93µs
WhenI calculate "₫100"47µs
Thenthe calculation fails mentioning "unsupported currency"42µs
Percent on a currency amount is refusedpassed113µs
WhenI calculate "$9%"69µs
Thenthe calculation fails mentioning "can't apply % to a currency amount"42µs
A plain number absorbs into the currencyoutline · 3passed
$10 + 5, $15.00passed121µs
WhenI calculate "$10 + 5"79µs
Thenthe log echoes "$15.00"39µs
5 + $10, $15.00passed102µs
WhenI calculate "5 + $10"67µs
Thenthe log echoes "$15.00"32µs
$10 * 3, $30.00passed100µs
WhenI calculate "$10 * 3"66µs
Thenthe log echoes "$30.00"31µs
Mixing currencies is refusedoutline · 3passed
$10 + €5passed165µs
WhenI calculate "$10 + €5"114µs
Thenthe calculation fails mentioning "can't mix currencies"47µs
€10 - $5passed129µs
WhenI calculate "€10 - $5"83µs
Thenthe calculation fails mentioning "can't mix currencies"43µs
$10 * £2passed118µs
WhenI calculate "$10 * £2"74µs
Thenthe calculation fails mentioning "can't mix currencies"41µs
The currency survives every arithmetic operatoroutline · 4passed
$10 * $2, $20.00passed115µs
WhenI calculate "$10 * $2"76µs
Thenthe log echoes "$20.00"36µs
$10 / $2, $5.00passed182µs
WhenI calculate "$10 / $2"138µs
Thenthe log echoes "$5.00"39µs
$10 + $2, $12.00passed108µs
WhenI calculate "$10 + $2"73µs
Thenthe log echoes "$12.00"32µs
$10 - $2, $8.00passed167µs
WhenI calculate "$10 - $2"105µs
Thenthe log echoes "$8.00"55µs
Negation keeps the currency and puts the sign outside the symbolpassed186µs
WhenI calculate "-$1234.5"82µs
Thenthe result is "Money(-1234.5, "USD")"43µs
Andthe log echoes "-$1,234.50"55µs
Grouped numbers echo their groupingoutline · 6passed
138,561, 138561, 138,561passed163µs
WhenI calculate "138,561"79µs
Thenthe result is "138561"38µs
Andthe log echoes "138,561"41µs
138,561 * 9%, 12470.49, 12,470.49passed172µs
WhenI calculate "138,561 * 9%"89µs
Thenthe result is "12470.49"39µs
Andthe log echoes "12,470.49"39µs
1,000 + 1, 1001, 1,001passed153µs
WhenI calculate "1,000 + 1"77µs
Thenthe result is "1001"34µs
Andthe log echoes "1,001"38µs
1,234,567, 1234567, 1,234,567passed161µs
WhenI calculate "1,234,567"71µs
Thenthe result is "1234567"42µs
Andthe log echoes "1,234,567"42µs
12,470.49 * 2, 24940.98, 24,940.98passed173µs
WhenI calculate "12,470.49 * 2"90µs
Thenthe result is "24940.98"38µs
Andthe log echoes "24,940.98"39µs
-138,561, -138561, -138,561passed163µs
WhenI calculate "-138,561"63µs
Thenthe result is "-138561"52µs
Andthe log echoes "-138,561"42µs
Grouped currency composes through a subexpressionpassed190µs
WhenI calculate "$10,000 + ($15,000 * 5%)"106µs
Thenthe result is "Money(10750, "USD")"40µs
Andthe log echoes "$10,750.00"39µs
The argument separator wins over groupingpassed106µs
WhenI calculate "max(138,561)"81µs
Thenthe result is "561"23µs
Grouping is suppressed inside an array literalpassed160µs
WhenI calculate "sum([1,500])"110µs
Thenthe result is "501"44µs
Malformed thousands groups are refusedoutline · 3passed
1,23passed103µs
WhenI calculate "1,23"56µs
Thenthe calculation fails mentioning "thousands group"44µs
1,2345passed85µs
WhenI calculate "1,2345"41µs
Thenthe calculation fails mentioning "thousands group"41µs
1234,567passed81µs
WhenI calculate "1234,567"38µs
Thenthe calculation fails mentioning "thousands group"40µs

Namespaces group declarations under a qualified name

33/33 scenarios passed · 0µs
A namespace exposes its data types by qualified namepassed260µs
GivenI calculate "namespace Geo { data Point { x: Number, y: Number } }"108µs
WhenI calculate "Geo::Point(x: 3, y: 4).x"113µs
Thenthe result is "3"35µs
A namespaced record renders and re-parses with its qualified namepassed407µs
GivenI calculate "namespace Geo { data Point { x: Number, y: Number } }"220µs
WhenI calculate "Geo::Point(x: 3, y: 4)"133µs
Thenthe result is "Geo::Point(x: 3, y: 4)"46µs
A field referencing a sibling type resolves within the namespacepassed405µs
GivenI calculate "namespace Geo { data Point { x: Number, y: Number }; data Line { a: Point, b: Point } }"143µs
AndI calculate "seg = Geo::Line(a: Geo::Point(x: 1, y: 1), b: Geo::Point(x: 4, y: 5))"164µs
WhenI calculate "seg.b.x"58µs
Thenthe result is "4"33µs
List fields nest namespaced recordspassed492µs
GivenI calculate "namespace Bits { data Field { name: String, flags: [String] }; data Format { fields: [Field] } }"144µs
AndI calculate "f = Bits::Format(fields: [Bits::Field(name: "owner", flags: ["r", "w", "x"])])"123µs
WhenI calculate "len(f.fields)"65µs
Thenthe result is "1"33µs
WhenI calculate "len(f.fields[0].flags)"87µs
Thenthe result is "3"32µs
A namespaced function resolves sibling functions and types unqualifiedpassed802µs
GivenI calculate "namespace Geo { data Point { x: Number, y: Number }; dist(p: Point) = sqrt(p.x^2 + p.y^2); origin() = Point(x: 0, y: 0) }"219µs
WhenI calculate "Geo::dist(Geo::Point(x: 3, y: 4))"346µs
Thenthe result is "5"35µs
WhenI calculate "Geo::dist(Geo::origin())"160µs
Thenthe result is "0"35µs
A namespaced function calls a sibling function unqualifiedpassed343µs
GivenI calculate "namespace M { a(n) = b(n) + 1; b(n) = n * 2 }"195µs
WhenI calculate "M::a(10)"111µs
Thenthe result is "21"32µs
Namespaced recursion resolves itself through the home namespacepassed288µs
GivenI calculate "namespace R { fact(n) = if(n <= 1, 1, n * fact(n - 1)) }"165µs
WhenI calculate "R::fact(6)"91µs
Thenthe result is "720"28µs
Qualified construction validates and resolves loudlyoutline · 2passed
Bits::Format(fields: [5]), is a Bits::Fieldpassed367µs
GivenI calculate "namespace Bits { data Field { name: String }; data Format { fields: [Field] } }"166µs
WhenI calculate "Bits::Format(fields: [5])"159µs
Thenthe calculation fails mentioning "is a Bits::Field"35µs
Bits::Nope(x: 1), unknown functionpassed251µs
GivenI calculate "namespace Bits { data Field { name: String }; data Format { fields: [Field] } }"113µs
WhenI calculate "Bits::Nope(x: 1)"92µs
Thenthe calculation fails mentioning "unknown function"41µs
A namespace needs at least one declarationpassed108µs
WhenI calculate "namespace Empty { }"65µs
Thenthe calculation fails mentioning "at least one declaration"39µs
Namespace members are separated by a semicolonpassed138µs
WhenI calculate "namespace Bad { data A { x: Number } data B { y: Number } }"91µs
Thenthe calculation fails mentioning "separate namespace declarations with ';'"44µs
A namespace exposes a constant by qualified namepassed193µs
GivenI calculate "namespace Phys { c = 299792458 }"98µs
WhenI calculate "Phys::c"54µs
Thenthe result is "299792458"37µs
A namespaced function uses a sibling constant unqualifiedpassed294µs
GivenI calculate "namespace Circle { k = 3.14159; area(r) = k * r * r }"139µs
WhenI calculate "Circle::area(10)"106µs
Thenthe result is "314.159"43µs
An imported namespace's constant resolves unqualifiedpassed350µs
GivenI calculate "namespace Phys { c = 299792458 }"122µs
AndI calculate "import Phys"127µs
WhenI calculate "c"56µs
Thenthe result is "299792458"37µs
Importing a constant that collides with a global is loudpassed312µs
GivenI calculate "speed = 5"76µs
AndI calculate "namespace V { data Q { x: Number }; speed = 10 }"116µs
WhenI calculate "import V"69µs
Thenthe calculation fails mentioning "would shadow 'speed'"45µs
A nested namespace resolves by its full qualified namepassed531µs
GivenI calculate "namespace A { data Point { x: Number, y: Number }; namespace B { dist(p: Point) = sqrt(p.x^2 + p.y^2) } }"195µs
WhenI calculate "A::B::dist(A::Point(x: 3, y: 4))"292µs
Thenthe result is "5"38µs
An inner member uses a parent constant and function unqualifiedpassed285µs
GivenI calculate "namespace A { base = 10; twice(n) = n * 2; namespace B { f(x) = twice(x) + base } }"152µs
WhenI calculate "A::B::f(5)"92µs
Thenthe result is "20"35µs
A nested record renders and re-parses with its full qualified namepassed253µs
GivenI calculate "namespace A { namespace B { data Point { x: Number, y: Number } } }"106µs
WhenI calculate "A::B::Point(x: 3, y: 4)"100µs
Thenthe result is "A::B::Point(x: 3, y: 4)"43µs
A nested namespace survives save and reopenpassed637µs
GivenI calculate "namespace A { k = 7; namespace B { triple(n) = n * 3 } }"115µs
Whenthe workbook is saved and reopened396µs
AndI calculate "A::B::triple(A::k)"88µs
Thenthe result is "21"32µs
import brings a namespace's members into scope unqualifiedpassed890µs
GivenI calculate "namespace Geo { data Point { x: Number, y: Number }; dist(p: Point) = sqrt(p.x^2 + p.y^2) }"209µs
AndI calculate "import Geo"88µs
WhenI calculate "dist(Point(x: 3, y: 4))"268µs
Thenthe result is "5"36µs
WhenI calculate "Geo::dist(Geo::Point(x: 6, y: 8))"245µs
Thenthe result is "10"34µs
Importing an unknown namespace errorspassed113µs
WhenI calculate "import Nope"73µs
Thenthe calculation fails mentioning "no namespace 'Nope'"37µs
Importing a name that collides with a global is loudpassed255µs
GivenI calculate "data Pt { x: Number }"75µs
AndI calculate "namespace NS { data Pt { x: Number } }"74µs
WhenI calculate "import NS"60µs
Thenthe calculation fails mentioning "would shadow 'Pt'"40µs
Importing a name that collides with a builtin is loudpassed189µs
GivenI calculate "namespace M2 { sqrt(x) = x * x }"89µs
WhenI calculate "import M2"56µs
Thenthe calculation fails mentioning "would shadow 'sqrt'"39µs
Re-importing a namespace is a harmless no-oppassed383µs
GivenI calculate "namespace Ok { area(r) = 3 * r * r }"104µs
AndI calculate "import Ok"54µs
AndI calculate "import Ok"67µs
WhenI calculate "area(2)"109µs
Thenthe result is "12"39µs
A builtin is reachable by its module, and the bare name stays globalpassed713µs
WhenI calculate "Core::sqrt(16)"252µs
Thenthe result is "4"38µs
WhenI calculate "Core::sqrt(16) == sqrt(16)"379µs
Thenthe result is "1"36µs
A qualified builtin must belong to that modulepassed152µs
WhenI calculate "Finance::sqrt(16)"104µs
Thenthe calculation fails mentioning "unknown function 'Finance::sqrt'"44µs
A qualified builtin works as a valuepassed569µs
WhenI calculate "map(Core::sqrt, [4, 9, 16])"519µs
Thenthe result is "[2, 3, 4]"45µs
Importing a builtin module is a no-op — its members are in the preludepassed226µs
GivenI calculate "import Stats"63µs
WhenI calculate "median(1, 2, 3, 4, 5)"123µs
Thenthe result is "3"36µs
A namespace and its import survive save and reopenpassed1ms
GivenI calculate "namespace Geo { data Point { x: Number, y: Number }; dist(p: Point) = sqrt(p.x^2 + p.y^2) }"171µs
AndI calculate "import Geo"60µs
Whenthe workbook is saved and reopened328µs
AndI calculate "Geo::dist(Geo::Point(x: 3, y: 4))"263µs
Thenthe result is "5"36µs
WhenI calculate "dist(Point(x: 6, y: 8))"238µs
Thenthe result is "10"35µs
A namespaced constant survives save and reopenpassed539µs
GivenI calculate "namespace Phys { c = 299792458; energy(m) = m * c * c }"122µs
Whenthe workbook is saved and reopened198µs
AndI calculate "Phys::c"54µs
Thenthe result is "299792458"36µs
WhenI calculate "Phys::energy(2)"83µs
Thenthe result is "179751035747363528"37µs
An IPv4 subnetting toolkit composes from namespaces and fixed-width intspassed1ms
GivenI calculate "namespace Net { ip(a,b,c,d) = UInt32(a)*16777216 + UInt32(b)*65536 + UInt32(c)*256 + UInt32(d); mask(p) = UInt32(2^32 - 2^(32 - p)); wildcard(p) = bitNot(mask(p)); network(addr, p) = bitAnd(addr, mask(p)); broadcast(addr, p) = bitOr(addr, wildcard(p)); hosts(p) = 2^(32 - p) - 2 }"445µs
AndI calculate "addr = Net::ip(192, 168, 1, 130)"210µs
WhenI calculate "Net::network(addr, 24) == 3232235776"158µs
Thenthe result is "1"36µs
WhenI calculate "Net::broadcast(addr, 24) == 3232236031"152µs
Thenthe result is "1"34µs
WhenI calculate "Net::hosts(24)"84µs
Thenthe result is "254"41µs
WhenI calculate "Net::network(addr, 26) == 3232235904"146µs
Thenthe result is "1"33µs
WhenI calculate "Net::hosts(26)"79µs
Thenthe result is "62"47µs
IPv6 subnetting scales the same toolkit to a 128-bit UInt128passed2ms
GivenI calculate "namespace Net6 { mask(p) = UInt128(2^128 - 2^(128 - p)); network(addr, p) = bitAnd(addr, mask(p)); hosts(p) = 2^(128 - p); hextet(addr, i) = bitAnd(bitShift(addr, -16 * (7 - i)), 65535) }"350µs
AndI calculate "addr = UInt128(2) * 2^112 + UInt128(0xdb8) * 2^96 + UInt128(0xabcd)"317µs
WhenI calculate "Net6::hextet(addr, 0) == 2"195µs
Thenthe result is "1"41µs
WhenI calculate "Net6::hextet(addr, 1) == 3512"150µs
Thenthe result is "1"34µs
WhenI calculate "Net6::network(addr, 64) == bitAnd(addr, UInt128(2^128 - 2^64))"251µs
Thenthe result is "1"34µs
WhenI calculate "Net6::hosts(64)"118µs
Thenthe result is "18446744073709551616"48µs
A MAC address splits into OUI and device with a UInt64passed519µs
GivenI calculate "mac = UInt64(0x001B44113AB7)"141µs
WhenI calculate "bitAnd(bitShift(mac, -24), 0xFFFFFF) == 0x001B44"172µs
Thenthe result is "1"38µs
WhenI calculate "bitAnd(mac, 0xFFFFFF) == 0x113AB7"125µs
Thenthe result is "1"34µs

Inspecting the workbook

13/13 scenarios passed · 0µs
Workbook reports its sheetspassed588µs
Givena sheet named "Budget"81µs
WhenI calculate "Workbook.count"457µs
Thenthe result is "2"43µs
Worksheet names are readablepassed206µs
Givena sheet named "Budget"56µs
WhenI calculate "Workbook.worksheets[1].name == "Budget""111µs
Thenthe result is "1"33µs
A worksheet is reachable by namepassed185µs
Givena sheet named "Budget"49µs
WhenI calculate "Workbook.worksheets["Budget"].name == "Budget""94µs
Thenthe result is "1"36µs
A negative index counts from the endpassed220µs
Givena sheet named "Budget"70µs
WhenI calculate "Workbook.worksheets[-1].name == "Budget""110µs
Thenthe result is "1"35µs
Reading a cell's value through the object graphpassed380µs
Givena sheet named "Budget"53µs
Andcell B:1 on "Budget" contains "1200"142µs
WhenI calculate "Workbook.worksheets["Budget"].cell("B", 1).value * 2"140µs
Thenthe result is "2400"38µs
A cell value is reachable by positionpassed238µs
Givencell A:1 contains "=2 + 3"87µs
WhenI calculate "Workbook.worksheets[0].cell("A", 1).value"117µs
Thenthe result is "5"30µs
The flat cell() accessor reads the active sheetpassed249µs
Givencell A:1 contains "42"85µs
WhenI calculate "cell("A", 1).value"106µs
Thenthe result is "42"46µs
The flat cell() accessor reaches another sheet by namepassed276µs
Givena sheet named "Budget"53µs
Andcell A:1 on "Budget" contains "99"83µs
WhenI calculate "cell("Budget", "A", 1).value"98µs
Thenthe result is "99"35µs
sheetNames() lists every sheetpassed184µs
Givena sheet named "Budget"62µs
WhenI calculate "len(sheetNames())"82µs
Thenthe result is "2"34µs
rowCount() reports the grid sizepassed96µs
WhenI calculate "rowCount()"61µs
Thenthe result is "1000"32µs
A formula reading a cell through reflection recomputes livepassed250µs
Givencell A:1 contains "10"86µs
Andcell B:1 contains "=cell("A", 1).value + 1"96µs
Thencell B:1 shows "11"64µs
A user's own function shadows a reflection accessorpassed249µs
WhenI calculate "cell(x) = x * 10"122µs
AndI calculate "cell(5)"85µs
Thenthe result is "50"36µs
An unknown sheet is reported clearlypassed154µs
WhenI calculate "cell("Nope", "A", 1).value"110µs
Thenthe calculation fails mentioning "unknown sheet"41µs

Scripts — multi-line sources split into logical statements

8/8 scenarios passed · 0µs
A pretty multi-line namespace block runs as one statementpassed384µs
WhenI run the script:343µs
Thenthe result is "3"38µs
Parentheses continue a statement across linespassed151µs
WhenI run the script:113µs
Thenthe result is "10"34µs
Brackets continue a statement across linespassed138µs
WhenI run the script:100µs
Thenthe result is "3"35µs
Shebang and comment lines pass between statementspassed158µs
WhenI run the script:97µs
Thenthe result is "2"52µs
A first-line comment documents a multi-line definitionpassed278µs
WhenI run the script:146µs
WhenI calculate "man triple"70µs
Thendocumentation is shown mentioning "three of x"56µs
Braces inside a string do not open a continuationpassed147µs
WhenI run the script:103µs
Thenthe result is "13"40µs
An unclosed block at end of input is a loud errorpassed106µs
WhenI run the script:61µs
Thenthe calculation fails mentioning "unterminated"42µs
Thousands grouping works inside a continued statementpassed203µs
WhenI run the script:116µs
Thenthe result is "12470.49"39µs
Andthe log echoes "12,470.49"44µs

Working in the grid

21/21 scenarios passed · 0µs
Cells reference each otherpassed222µs
Givencell B:1 contains "1200"90µs
Andcell B:2 contains "=B:1 * 2"71µs
Thencell B:2 shows "2400"56µs
Labels never become errorspassed125µs
Givencell A:1 contains "Q1 revenue"61µs
Thencell A:1 shows "Q1 revenue"62µs
A comment cell is a note that holds no valuepassed140µs
Givencell A:1 contains "# tentative — revisit in Q4"78µs
Thencell A:1 shows "# tentative — revisit in Q4"59µs
A note cell is skipped in ranges and errors when referencedpassed399µs
Giventhe sheet contains:103µs
Andcell B:4 contains "=sum(B:1..B:3)"71µs
Thencell B:4 shows "150"87µs
Andcell B:5 contains "=B:2 + 1"71µs
Thencell B:5 shows an error mentioning "not a number"60µs
A trailing comment on a formula is kept and ignored by evaluationpassed202µs
Givencell B:1 contains "200"72µs
Andcell B:2 contains "=B:1 * 1.08 # with sales tax"74µs
Thencell B:2 shows "216"50µs
Ranges aggregate a columnpassed249µs
Giventhe sheet contains:107µs
Andcell B:4 contains "=sum(B:1..B:3)"68µs
Thencell B:4 shows "400"70µs
A named cell reads like prosepassed270µs
Givencell B:7 contains "0.08"66µs
Andcell B:7 is named "Projected Rate"73µs
Andcell A:1 contains "='Projected Rate' * 100"74µs
Thencell A:1 shows "8"50µs
Sheet definitions belong to their cellspassed369µs
Givencell A:1 contains "rate = 0.1"84µs
Andcell A:2 contains "=100 * rate"66µs
Thencell A:1 shows "𝑖 rate"56µs
Andcell A:2 shows "10"54µs
WhenI calculate "rate = 0.5"63µs
Thenthe calculation fails mentioning "defined in cell"40µs
A function defined in a cell is callablepassed288µs
Givencell A:1 contains "tax(x) = x * 1.0825"96µs
Andcell A:2 contains "=tax(200)"80µs
Thencell A:1 shows "λ tax(x)"48µs
Andcell A:2 shows "216.5"59µs
A slider is a value with a rangepassed294µs
Givencell A:1 contains "r = slider(0.11, 0, 0.2)"106µs
Andcell A:2 contains "=r * 100"62µs
Thencell A:1 is a slider set to "0.11"69µs
Andcell A:2 shows "11"54µs
The log sees the sheetpassed157µs
Givencell B:1 contains "1200"59µs
WhenI calculate "B:1 * 2"64µs
Thenthe result is "2400"31µs
Explicit markers override auto-detectionpassed265µs
Givencell A:1 contains ""123""48µs
Andcell A:2 contains "=12 * rte"70µs
Thencell A:1 shows "123"71µs
Andcell A:2 shows an error mentioning "unknown variable"70µs
A formula mistake is an error, not a guesspassed222µs
Givencell B:1 contains "100"86µs
Andcell B:2 contains "B:1 / 0"68µs
Thencell B:2 shows an error mentioning "division by zero"64µs
Empty cells read as zeropassed121µs
Givencell A:1 contains "=B:9 + 5"71µs
Thencell A:1 shows "5"46µs
Circular references are caught, not infinitepassed218µs
Givencell A:1 contains "=A:2 + 1"68µs
Andcell A:2 contains "=A:1 + 1"70µs
Thencell A:1 shows an error mentioning "circular reference"75µs
Referencing a text cell is an errorpassed204µs
Givencell A:1 contains "Q1 revenue"71µs
Andcell A:2 contains "=A:1 * 2"64µs
Thencell A:2 shows an error mentioning "not a number"65µs
The controls family holds valuespassed535µs
Givencell A:1 contains "flag = checkbox(true)"83µs
Andcell A:2 contains "n = stepper(5, 1, 20)"94µs
Andcell A:3 contains "region = dropdown("EU", ["EU", "US"])"78µs
Andcell B:1 contains "=if(flag, n * 2, 0)"85µs
Andcell B:2 contains "=if(region == "EU", 1, 2)"80µs
Thencell B:1 shows "10"61µs
Andcell B:2 shows "1"48µs
A column of checkboxes counts its checked onespassed250µs
Giventhe sheet contains:111µs
Andcell C:4 contains "=sum(C:1..C:3)"64µs
Thencell C:4 shows "2"72µs
Formulas reach across worksheets by namepassed360µs
Givena sheet named "Budget"50µs
Andcell B:1 on "Budget" contains "1200"68µs
Andcell A:1 contains "=Budget!B:1 * 2"66µs
Thencell A:1 shows "2400"47µs
WhenI calculate "sum(Budget!B:1..B:1) + 1"88µs
Thenthe result is "1201"34µs
A renamed-away sheet breaks loudly, not silentlypassed119µs
Givencell A:1 contains "=Nowhere!B:1"64µs
Thencell A:1 shows an error mentioning "unknown sheet"52µs
A workbook round-trips through its file formatpassed1ms
Givena sheet named "Loan"43µs
Andcell B:1 on "Loan" contains "350000"69µs
Andcell A:1 contains "=Loan!B:1 / 100"67µs
Andcell B:7 contains "0.08"57µs
Andcell B:7 is named "Projected Rate"42µs
Andcell A:2 contains "='Projected Rate' * 100"66µs
WhenI calculate "growth = 1.5"61µs
Andthe workbook is saved and reopened339µs
Thencell A:1 shows "3500"94µs
Andcell A:2 shows "8"48µs
WhenI calculate "growth * 2"62µs
Thenthe result is "3"42µs

Strings, arrays, maps, and the functions that work them

45/45 scenarios passed · 0µs
Text and structure functionsoutline · 30passed
len([1, 2, 3]), 3passed176µs
WhenI calculate "len([1, 2, 3])"127µs
Thenthe result is "3"44µs
len("hello"), 5passed102µs
WhenI calculate "len("hello")"69µs
Thenthe result is "5"29µs
len({a: 1, b: 2}), 2passed160µs
WhenI calculate "len({a: 1, b: 2})"118µs
Thenthe result is "2"38µs
first([5, 6, 7]), 5passed132µs
WhenI calculate "first([5, 6, 7])"94µs
Thenthe result is "5"34µs
last([5, 6, 7]), 7passed132µs
WhenI calculate "last([5, 6, 7])"95µs
Thenthe result is "7"34µs
keys({name: "Ada", age: 36}), ["name", "age"]passed155µs
WhenI calculate "keys({name: "Ada", age: 36})"99µs
Thenthe result is "["name", "age"]"52µs
values({a: 1, b: 2}), [1, 2]passed183µs
WhenI calculate "values({a: 1, b: 2})"139µs
Thenthe result is "[1, 2]"40µs
sum(values({a: 1, b: 2})), 3passed152µs
WhenI calculate "sum(values({a: 1, b: 2}))"114µs
Thenthe result is "3"35µs
concat("Q", 1, "-", 2026), "Q1-2026"passed143µs
WhenI calculate "concat("Q", 1, "-", 2026)"105µs
Thenthe result is ""Q1-2026""36µs
concat([1, 2], [3]), [1, 2, 3]passed138µs
WhenI calculate "concat([1, 2], [3])"96µs
Thenthe result is "[1, 2, 3]"39µs
"Q" + 1, "Q1"passed128µs
WhenI calculate ""Q" + 1"84µs
Thenthe result is ""Q1""40µs
"a" + "b" + "c", "abc"passed92µs
WhenI calculate ""a" + "b" + "c""57µs
Thenthe result is ""abc""33µs
"abc"[0], "a"passed106µs
WhenI calculate ""abc"[0]"70µs
Thenthe result is ""a""34µs
slice("hello", 0, 2), "he"passed128µs
WhenI calculate "slice("hello", 0, 2)"90µs
Thenthe result is ""he""34µs
slice("hello", 2), "llo"passed110µs
WhenI calculate "slice("hello", 2)"73µs
Thenthe result is ""llo""35µs
slice("hello", 1, 4), "ell"passed139µs
WhenI calculate "slice("hello", 1, 4)"100µs
Thenthe result is ""ell""35µs
slice("hello", 0, len("hello")), "hello"passed127µs
WhenI calculate "slice("hello", 0, len("hello"))"90µs
Thenthe result is ""hello""35µs
slice([1, 2, 3, 4], 1, 3), [2, 3]passed162µs
WhenI calculate "slice([1, 2, 3, 4], 1, 3)"116µs
Thenthe result is "[2, 3]"42µs
slice([1, 2, 3, 4], 2), [3, 4]passed147µs
WhenI calculate "slice([1, 2, 3, 4], 2)"107µs
Thenthe result is "[3, 4]"37µs
split("a,b,c", ","), ["a", "b", "c"]passed132µs
WhenI calculate "split("a,b,c", ",")"86µs
Thenthe result is "["a", "b", "c"]"42µs
split("nosep", ","), ["nosep"]passed105µs
WhenI calculate "split("nosep", ",")"70µs
Thenthe result is "["nosep"]"32µs
len(split("a,b,c", ",")), 3passed113µs
WhenI calculate "len(split("a,b,c", ","))"76µs
Thenthe result is "3"33µs
charCode("A"), 65passed99µs
WhenI calculate "charCode("A")"63µs
Thenthe result is "65"33µs
fromCharCode(65), "A"passed112µs
WhenI calculate "fromCharCode(65)"77µs
Thenthe result is ""A""33µs
fromCharCode(charCode("z")), "z"passed122µs
WhenI calculate "fromCharCode(charCode("z"))"86µs
Thenthe result is ""z""33µs
[[1, 2], [3, 4]][1][0], 3passed172µs
WhenI calculate "[[1, 2], [3, 4]][1][0]"120µs
Thenthe result is "3"48µs
{a: [1, 2]}.a[1], 2passed160µs
WhenI calculate "{a: [1, 2]}.a[1]"119µs
Thenthe result is "2"37µs
[1, 2] == [1, 2], 1passed166µs
WhenI calculate "[1, 2] == [1, 2]"122µs
Thenthe result is "1"40µs
{a: 1, b: 2} == {b: 2, a: 1}, 1passed154µs
WhenI calculate "{a: 1, b: 2} == {b: 2, a: 1}"116µs
Thenthe result is "1"35µs
"x" != 5, 1passed94µs
WhenI calculate ""x" != 5"59µs
Thenthe result is "1"31µs
Structure mistakes explain themselvesoutline · 11passed
[1, 2][5], out of rangepassed138µs
WhenI calculate "[1, 2][5]"92µs
Thenthe calculation fails mentioning "out of range"43µs
{a: 1}.b, no key 'b'passed124µs
WhenI calculate "{a: 1}.b"76µs
Thenthe calculation fails mentioning "no key 'b'"43µs
first([]), empty arraypassed104µs
WhenI calculate "first([])"67µs
Thenthe calculation fails mentioning "empty array"34µs
sum(["a"]), works on numberspassed114µs
WhenI calculate "sum(["a"])"71µs
Thenthe calculation fails mentioning "works on numbers"41µs
"a" * 2, expected a numberpassed101µs
WhenI calculate ""a" * 2"64µs
Thenthe calculation fails mentioning "expected a number"34µs
{a: 1, a: 2}, duplicate keypassed128µs
WhenI calculate "{a: 1, a: 2}"83µs
Thenthe calculation fails mentioning "duplicate key"41µs
slice("abc", 0, 9), out of rangepassed130µs
WhenI calculate "slice("abc", 0, 9)"89µs
Thenthe calculation fails mentioning "out of range"38µs
slice("abc", -1, 2), out of rangepassed136µs
WhenI calculate "slice("abc", -1, 2)"94µs
Thenthe calculation fails mentioning "out of range"40µs
split("abc", ""), non-empty separatorpassed109µs
WhenI calculate "split("abc", "")"71µs
Thenthe calculation fails mentioning "non-empty separator"35µs
charCode("ab"), single characterpassed124µs
WhenI calculate "charCode("ab")"79µs
Thenthe calculation fails mentioning "single character"42µs
fromCharCode(-1), valid characterpassed149µs
WhenI calculate "fromCharCode(-1)"101µs
Thenthe calculation fails mentioning "valid character"43µs
charCode enables ordered character-class testspassed297µs
WhenI calculate "and(charCode("5") >= charCode("0"), charCode("5") <= charCode("9"))"120µs
Thenthe result is "1"35µs
WhenI calculate "and(charCode("x") >= charCode("0"), charCode("x") <= charCode("9"))"104µs
Thenthe result is "0"33µs
Filter and reduce shape data like a user thinkspassed308µs
WhenI calculate "filter(x -> x > 1, [1, 2, 3])"140µs
Thenthe result is "[2, 3]"40µs
WhenI calculate "reduce((a, b) -> a + b, [], 42)"90µs
Thenthe result is "42"33µs
Lambdas live in variables and close over parameterspassed434µs
WhenI calculate "f = x -> x * 2"74µs
AndI calculate "f(21)"71µs
Thenthe result is "42"33µs
WhenI calculate "scale(arr, n) = map(x -> x * n, arr)"95µs
AndI calculate "scale([1, 2, 3], 10)"116µs
Thenthe result is "[10, 20, 30]"38µs
A named function reference follows redefinitionpassed331µs
WhenI calculate "h(x) = x + 1"89µs
AndI calculate "alias = h"57µs
AndI calculate "h(x) = x + 100"74µs
AndI calculate "alias(1)"70µs
Thenthe result is "101"34µs