Mica’s math unit is the first standard-library user of the
generics machinery, and its design fits in one
sentence: the language’s mathematics lives in one namespace, written in
Mica where a body can say it and realized by the compiler where only the
machine can.
The example is
examples/MathUnit.
Build and run it:
make -C mica-container/examples/MathUnit runOne source, every width
Min, Max, Clamp, Abs and Sign are each a short generic function
over a constrained type parameter, monomorphized per concrete type:
w := Clamp(12, 0, 10); { int64: 10 }
tiny := Clamp((0.25 as float32), (0.0 as float32), (1.0 as float32));The float32 answer stays float32 — no widening to double and back, which
is the fidelity a generic road exists to buy. Each constraint is exactly
what the body does: comparison for the order family, comparison and
negation for Abs, the numeric literals beside both for Sign.
The integer verbs are Gcd (Euclid), Lcm through it, and PowInt by
binary squaring — integral types only, because an integer power of an
integer is an integer fact.
Constants are declarations
Pi, E, Tau and the machine epsilons are spelled as what they are —
Tau is literally the expression 2.0 * Pi — so Tau / Pi = 2.000000
is arithmetic, not folklore.
Classification through arithmetic
IsNan and IsInf read IEEE facts with no bit tricks and no C call: a
value that disagrees with itself is the not-a-number, and a nonzero value
that survives exact halving unchanged is an infinity.
while not IsInf(inf) do
inf := inf * inf * 16.0;
nan := inf - inf;Equality is exact; tolerance is spelled
A float comparison computes precisely what the runtime instruction
computes — at compile time and at run time, the bit-exact doctrine — so
0.1 + 0.2 = 0.3 is honestly False, and the place a tolerance lives is
a verb that names one:
ApproxEqual(f, 0.3, Epsilon64 * 4.0) { True — at a tolerance you chose }The transcendentals are intrinsics
Sqrt, Exp, Ln, Tanh, Erf and FusedMultiplyAdd are the unit’s
too, and they are not functions with bodies: the compiler realizes each
one at its call site. A square root becomes the processor’s own instruction —
sqrtsd on x86-64, fsqrt on AArch64 — and so does the fused
multiply-add, while each transcendental becomes one call of the platform’s
C math library in the operand’s own width: expf, logf, tanhf and
erff for a float32, exp, log, tanh and erf for a float64.
That is the call GCC and Clang emit for the same expression, so a Mica
program computes the same bits as the same program in C on the same
machine. The square root and the fused multiply-add give the same bits on
every machine, because IEEE 754 rounds them exactly; the transcendentals give
the digits of the machine’s C library.
One import reaches the word at every shape, because the unit’s routine and
the vocabulary’s word of the same name are one overload pair — Sqrt over
a float64 is the instruction, Sqrt over a vector is the unit’s verb
computing it elementwise:
imp
Min, Max, Clamp, Abs, Sign, Gcd, Lcm, PowInt, ApproxEqual, IsNan, IsInf, Pi, Tau, Epsilon64, Sqrt : math;The whole of C’s library is one qualifier away: cstd.Sqrt(2.0) is
libm’s sqrt named at its use, which is what the
cstd namespace is for — C interop, by C’s own
names. math gives the same functions in the language’s own shapes and
widths.
What this does not do
- No overloading. One name, one declaration —
Minthe scalar pair lives here; the reductionMinimumlives with the reductions, Julia’s own split. - No integral mean, no silent conversions. Where a formula needs a fractional answer from integers, you spell the conversion.
- No epsilon hidden in
=. Equality is exact everywhere; tolerance isApproxEqual’s third argument, visible at every call.
Try it
Change the tolerance to Epsilon64 alone and watch ApproxEqual answer
False — the gap between 0.1 + 0.2 and 0.3 is real, measurable, and
exactly two ulps wide.
Next
The unit’s other half — the verbs over many elements — is the reductions family, where determinism becomes a promise about parallelism.