std/math — Fixed-point math

import std/math

A mathematics library that works entirely in Q8.8 fixed-point (the r16 type — see Type system). There is no floating-point hardware on the AVR, so every “real” value here is a 16-bit fixed-point number: 8 integer bits and 8 fractional bits, i.e. the true value scaled by 256.

Because of that representation, results are approximations with limited range (roughly ±128) and precision (steps of 1/256). The transcendental functions use series expansions and identities chosen to stay within 16-bit arithmetic; treat them as good engineering approximations, not IEEE-exact.

Angles for the trigonometric functions are given in whole degrees as u16 (not radians), which keeps the common case exact and avoids a fixed-point conversion at every call.

Constants

@pi() -> r16

π, Archimedes’ constant (≈ 3.14 in Q8.8).

@e() -> r16

e, Euler’s number (≈ 2.718).

@tau() -> r16

τ = 2π (≈ 6.283).

Rounding and sign

@abs($x: r16) -> r16

Absolute value of a signed fixed-point $x.

@fabs($x: r16) -> r16

Absolute value (floating-style alias of @abs for fixed-point values).

@ceil($x: r16) -> r16

Round $x up to the nearest integer value (toward +∞).

@floor($x: r16) -> r16

Round $x down to the nearest integer value (toward −∞).

@trunc($x: r16) -> r16

Round $x toward zero, discarding the fractional part.

@copysign($x: r16, $y: r16) -> r16

Return a value with the magnitude of $x and the sign of $y.

@fmod($x: r16, $y: r16) -> r16

Floating-style remainder of $x divided by $y.

Comparison and ranges

@min($a: r16, $b: r16) -> r16

The smaller of two signed fixed-point values.

@max($a: r16, $b: r16) -> r16

The larger of two signed fixed-point values.

@clamp($val: r16, $min_val: r16, $max_val: r16) -> r16

Constrain $val to the inclusive range [$min_val, $max_val].

@map($val: r16, $in_min: r16, $in_max: r16, $out_min: r16, $out_max: r16) -> r16

Linearly remap $val from the input range to the output range.

@isclose($a: r16, $b: r16, $rel_tol: r16) -> r16

Test whether $a and $b are within tolerance $rel_tol of each other.

Floating-status predicates

These exist for API completeness. A Q8.8 value is always finite, so the answers are constant — they let code that expects an isnan/isinf interface compile and behave sensibly.

@isnan($x: r16) -> r16

Whether $x is NaN. Fixed-point has no NaN, so this is always false.

@isinf($x: r16) -> r16

Whether $x is ±infinity. Fixed-point has no infinities.

@isfinite($x: r16) -> r16

Whether $x is finite (always true for a fixed-point value).

Powers, roots, exponentials, logs

@pow($base: r16, $exp: u16) -> r16

$base raised to the integer power $exp, by binary exponentiation (square-and-multiply).

@sqrt($x: r16) -> r16

Square root of $x, by digit-by-digit (binary) extraction.

@exp($x: r16) -> r16

e raised to the power $x, via a 5th-degree Maclaurin series. The input is capped at 5.0 to avoid 16-bit overflow.

@log($x: r16) -> r16

Natural logarithm ln($x), via range-reduction against e and a Taylor series.

@log2($x: r16) -> r16

Base-2 logarithm, computed as @log divided by ln 2.

@log10($x: r16) -> r16

Base-10 logarithm, computed as @log divided by ln 10.

Trigonometry

Angles are in degrees (u16) unless noted.

@sin($deg: u16) -> r16

Sine of $deg degrees, using quadrant symmetry.

@cos($deg: u16) -> r16

Cosine of $deg degrees (a 90° phase shift of sine).

@tan($deg: u16) -> r16

Tangent of $deg degrees, as sine over cosine (guards the zero-cosine case).

@radians($deg: u16) -> r16

Convert $deg degrees to radians (returned as Q8.8).

@degrees($rad: r16) -> u16

Convert $rad radians (Q8.8) to whole degrees.

@hypot($x: r16, $y: r16) -> r16

sqrt($x² + $y²), computed to avoid intermediate overflow.

@dist($x1: r16, $y1: r16, $x2: r16, $y2: r16) -> r16

Euclidean distance between the points ($x1,``$y1``) and ($x2,``$y2``).

Hyperbolic

@sinh($x: r16) -> r16

Hyperbolic sine.

@cosh($x: r16) -> r16

Hyperbolic cosine.

@tanh($x: r16) -> r16

Hyperbolic tangent, as sinh/cosh.

@asinh($x: r16) -> r16

Inverse hyperbolic sine.

@acosh($x: r16) -> r16

Inverse hyperbolic cosine.

@atanh($x: r16) -> r16

Inverse hyperbolic tangent.

Integer number theory

These take and return plain integers, not fixed-point.

@gcd($a: u16, $b: u16) -> u16

Greatest common divisor, by the Euclidean algorithm.

@lcm($a: u16, $b: u16) -> u16

Least common multiple of $a and $b.

@factorial($n: u8) -> u16

$n! computed iteratively. Overflows a u16 for $n above 8.

@fibonacci($n: u8) -> u16

The $n-th Fibonacci number, computed iteratively.

@perm($n: u8, $k: u8) -> u16

The number of permutations of $n items taken $k at a time.

@gamma($x: u8) -> u16

The Gamma function for integer input, i.e. ($x 1)!.

Example

import std/math

@main {
    ram imut $s:  r16 = @sin(30)             # angle in degrees -> ~0.5 (Q8.8)
    ram imut $rt: r16 = @sqrt(2.0)           # 2.0 is a fixed-point literal -> ~1.414
    ram imut $hi: r16 = @clamp(9.0, 0.0, 5.0) # 9 is above the max -> clamped to 5.0
    ram imut $g:  u16 = @gcd(48, 36)         # plain integers in/out -> 12
    loop * { }
}

Note

The functions with names beginning with an underscore — @_q88_mul, @_q88_div, @_sin_180 — are the internal fixed-point primitives the public functions are built on. You normally do not call them directly.