cheatah
Source

tests/purrc/math_sys_test.cpp

1// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).
2// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.
3// System-level test for the cheatah stdlib `math` module: ONE cohesive program
4// that exercises EVERY public function and constant declared in
5// stdlib/math/math.hpp (sqrt, cbrt, fabs, floor, ceil, trunc, round, exp, log,
6// log2, log10, sin, cos, tan, asin, acos, atan, atan2, hypot, fmod, copysign,
7// degrees, radians, isnan, isinf, isfinite, gcd, factorial, and the math-related
8// built-ins abs/min/max/pow, plus the constants pi/e/tau/inf/nan).
9//
10// Unlike the per-function compile-run tests (math_cr_test.cpp), this drives a
11// small geometry / number-theory pipeline that wires the functions together
12// (round_to uses round+pow; unit_point uses cos/sin/hypot; the combined section
13// reduces a fraction by gcd then norms it via pow/sqrt) and prints a single
14// deterministic multi-line report.
15//
16// The expected stdout below was captured by compiling and running the program
17// with the debug-build purrc + cheatah and confirming the output is identical
18// across repeated runs (md5 stable) before hardcoding it. Nothing here is
19// time/RNG dependent, so it is reproducible byte-for-byte.
21#include "e2e_harness.hpp"
23TEST(StdlibE2E, Math) {
24 e2e::expect_e2e("math_sys", R"PURR(import io
25import math
27# A cohesive pipeline exercising every public function/constant in stdlib/math.
28# It builds a little geometry/number-theory "report" from a few seeds.
30# --- helpers ---------------------------------------------------------------
32# Round a double to `digits` decimal places (uses round/pow).
33fn round_to(x, digits) {
34 let scale = math.pow(10, digits)
35 return math.round(x * scale) / scale
38# Polar -> cartesian distance check using trig + hypot.
39fn unit_point(theta) {
40 # returns hypot(cos, sin) which is 1 for any theta
41 return math.hypot(math.cos(theta), math.sin(theta))
44# --- 1) constants ----------------------------------------------------------
45io.print("== constants ==")
46io.print("pi", round_to(math.pi, 5), "e", round_to(math.e, 5), "tau", round_to(math.tau, 5))
47io.print("inf", math.inf, "nan", math.nan)
49# --- 2) roots and powers ---------------------------------------------------
50let r = math.sqrt(2.0) # ~1.41421
51let c = math.cbrt(27.0) # 3
52let p = math.pow(2, 10) # 1024
53io.print("== roots/powers ==")
54io.print("sqrt2", round_to(r, 5), "cbrt27", c, "pow", p)
56# --- 3) rounding family ----------------------------------------------------
57let v = -2.7
58io.print("== rounding ==")
59io.print("fabs", math.fabs(v), "floor", math.floor(v), "ceil", math.ceil(v))
60io.print("trunc", math.trunc(v), "round", math.round(v))
62# --- 4) exponentials / logs ------------------------------------------------
63let x = math.exp(1.0) # e
64io.print("== exp/log ==")
65io.print("exp1", round_to(x, 5))
66io.print("ln_e", round_to(math.log(math.e), 5), "log2_8", math.log2(8.0), "log10_1000", math.log10(1000.0))
68# --- 5) trigonometry -------------------------------------------------------
69let theta = math.pi / 4.0 # 45 degrees
70io.print("== trig ==")
71io.print("sin", round_to(math.sin(theta), 5), "cos", round_to(math.cos(theta), 5), "tan", round_to(math.tan(theta), 5))
72io.print("asin", round_to(math.asin(1.0), 5), "acos", round_to(math.acos(1.0), 5))
73io.print("atan", round_to(math.atan(1.0), 5), "atan2", round_to(math.atan2(1.0, 1.0), 5))
74io.print("unit_pt", round_to(unit_point(theta), 5))
76# --- 6) misc real ----------------------------------------------------------
77io.print("== misc ==")
78io.print("hypot", math.hypot(3.0, 4.0), "fmod", math.fmod(7.0, 3.0), "copysign", math.copysign(3.0, -1.0))
79io.print("degrees", math.degrees(math.pi), "radians", round_to(math.radians(180.0), 5))
81# --- 7) classification -----------------------------------------------------
82io.print("== classify ==")
83io.print("isnan", math.isnan(math.nan), "isinf", math.isinf(math.inf), "isfinite", math.isfinite(1.0))
85# --- 8) integer ops + builtins ---------------------------------------------
86io.print("== integer/builtins ==")
87io.print("gcd", math.gcd(48, 36), "fact", math.factorial(6))
88io.print("abs", math.abs(-7), "min", math.min(3, 9, 1, 5), "max", math.max(3, 9, 1, 5))
90# --- 9) a small combined computation ---------------------------------------
91# Reduce a fraction 48/36 by its gcd, then take pow/sqrt of the pieces.
92let g = math.gcd(48, 36)
93let num = 48 / g
94let den = 36 / g
95let combined = math.sqrt(math.pow(num, 2) + math.pow(den, 2))
96io.print("== combined ==")
97io.print("reduced", num, den, "norm", round_to(combined, 5))
98)PURR",
99 "== constants ==\n"
100 "pi 3.14159 e 2.71828 tau 6.28319\n"
101 "inf inf nan nan\n"
102 "== roots/powers ==\n"
103 "sqrt2 1.41421 cbrt27 3 pow 1024\n"
104 "== rounding ==\n"
105 "fabs 2.7 floor -3 ceil -2\n"
106 "trunc -2 round -3\n"
107 "== exp/log ==\n"
108 "exp1 2.71828\n"
109 "ln_e 1 log2_8 3 log10_1000 3\n"
110 "== trig ==\n"
111 "sin 0.70711 cos 0.70711 tan 1\n"
112 "asin 1.5708 acos 0\n"
113 "atan 0.7854 atan2 0.7854\n"
114 "unit_pt 1\n"
115 "== misc ==\n"
116 "hypot 5 fmod 1 copysign -3\n"
117 "degrees 180 radians 3.14159\n"
118 "== classify ==\n"
119 "isnan True isinf True isfinite True\n"
120 "== integer/builtins ==\n"
121 "gcd 12 fact 720\n"
122 "abs 7 min 1 max 9\n"
123 "== combined ==\n"
124 "reduced 4 3 norm 5\n");