std.math#
Introduced in rs-0.5.0. This is an initial, provisional package design, not the
complete math library. More functions and numeric facilities will be added;
APIs may be refined as the language develops.
The working tree after rs-0.5.0 expands this to 42 functions and six constants.
takepkg std.math;
func m{
out(math.min(3,7));
out(math.max(3,7));
out(math.abs(-5));
out(math.clamp(12,0,10));
out(math.min(1.0,2.0));
}
Output: 3, 7, 5, 10, 1, each on its own line.
Constants#
Added in the working tree after rs-0.5.0: math.PI, math.E, math.TAU,
math.SQRT2, math.LN2, and math.LN10. These are read-only float values, accessed
without parentheses. They use the backend's binary64 precision. TAU is twice PI;
LN2 and LN10 are natural logarithms. INF and NAN constants are not provided yet.
Original functions#
| Function | Result |
|---|---|
min(a,b) |
Smaller value |
max(a,b) |
Larger value |
abs(value) |
Absolute value |
clamp(value,low,high) |
Value constrained to the inclusive interval [low,high] |
Each function above accepts int, longint, or finite float values and returns the
same numeric type. Multi-argument calls require matching types. The exact argument
counts shown above are required. Wrong argument types/counts raise TypeError.
math.min(1,2.0) raises TypeError: 1 is an integer and 2.0 is a float.
Use math.min(float(1),2.0) to request the conversion. Runtime type tracking
preserves this distinction through variables, function calls, collections, copies,
and family fields, even when a float has an integral value.
clamp raises RangeError when low > high. Integer arguments/results must fit
their signed 32-bit or 64-bit range. abs(-2147483648) and the corresponding
minimum longint raise overflow errors. Non-finite floats, including NaN in any
argument of min/max/clamp, raise RangeError. Float zero ties are order-independent:
min chooses negative zero if either argument is negative zero, and max chooses
positive zero if either is positive zero. Abs returns positive zero. Clamp keeps
the input's zero sign when no bound replacement is needed.
Shared rules for the expansion#
Float-only functions reject integer arguments: use float(value) explicitly.
All arguments must be finite except for the three classification helpers. Invalid
domains, zero divisors, integer overflow, and non-finite results raise RangeError.
Non-finite arithmetic intermediates in the Marslang algorithms also raise errors.
Floating-point underflow to a finite subnormal or zero is allowed.
The signatures below specify exact argument counts. Wrong counts, wrong types,
or mixed numeric kinds raise TypeError. Angles for trig functions are in radians.
Sign helpers#
| Function | Input and result |
|---|---|
sign(x) |
Any finite numeric kind; returns int -1, 0, or 1; both zero signs return 0 |
signbit(x) |
Any finite numeric kind; returns boolean, true for negative values including float -0.0 |
copysign(x,y) |
Matching numeric kinds; returns magnitude of x with y's sign, preserving the kind |
Integers have no negative zero. copysign(INT_MIN,negative) is valid, while
requesting a positive result that cannot fit raises overflow. Float copysign
uses y's zero sign and retains a zero magnitude when x is zero.
Interpolation and angles#
All arguments and results in this section are floats.
| Function | Definition |
|---|---|
lerp(a,b,t) |
a + (b-a)*t; allows extrapolation outside t in [0,1] |
inverse_lerp(a,b,value) |
(value-a)/(b-a); a equal to b raises an error |
remap(value,in_low,in_high,out_low,out_high) |
Interpolate between output bounds using the input fraction; equal input bounds raise an error |
step(edge,x) |
0.0 when x is below edge, otherwise 1.0 |
radians(degrees) / degrees(radians) |
Convert angles |
Inverse interpolation and remapping allow reversed intervals and extrapolation; they do not clamp. Their direct formulas can overflow on extreme finite inputs, in which case they raise an error rather than silently return a non-finite result.
Rounding#
All four functions accept one float and return a float, even for integral results.
| Function | Behavior |
|---|---|
floor(x) |
Round toward negative infinity |
ceil(x) |
Round toward positive infinity |
trunc(x) |
Discard the fractional part, toward zero |
round(x) |
Nearest integer, with exact half ties going to the even integer |
Examples: round(2.5) is 2.0, round(3.5) is 4.0, and round(-2.5) is -2.0.
Negative inputs that round to zero keep negative zero; inspect it using signbit.
Powers and roots#
| Function | Types and behavior |
|---|---|
sqrt(x) |
Float to float; negative x raises an error |
cbrt(x) |
Float to float; negative inputs are supported |
hypot(a,b) |
Two floats to float; scaled to avoid overflow and underflow, written in Marslang |
pow(base,exponent) |
Matching numeric kinds; preserves the kind |
Integer pow requires a nonnegative exponent and computes exact integer powers with checked, bounded intermediates. Large exponents cannot create arbitrarily large temporary integers. Float pow permits negative exponents and rejects undefined real-valued results or overflow. Zero to the zero power returns one of the input kind. A negative base with a fractional float exponent raises an error.
Exponentials and logarithms#
All arguments/results are floats. These call the native rs.math primitives.
| Function | Behavior/domain |
|---|---|
exp(x) / exp2(x) |
e to the x / 2 to the x |
ln(x) / log2(x) / log10(x) |
Natural / base-2 / base-10 logarithm; x must be positive |
log(x,base) |
Arbitrary-base logarithm; x and base positive, base unequal to one |
expm1(x) |
Accurate exp(x) minus one for small x |
log1p(x) |
Accurate ln(1+x) for small x; x must exceed -1 |
Trigonometry#
All inputs/results are floats; angles use radians.
| Functions | Behavior/domain |
|---|---|
sin(x), cos(x), tan(x) |
Standard trigonometric functions |
asin(x), acos(x) |
Inverse sine/cosine; x in [-1,1] |
atan(x) |
Inverse tangent |
atan2(y,x) |
Quadrant-aware angle; note y comes first; signed-zero behavior follows the platform math library |
sinh(x), cosh(x), tanh(x) |
Hyperbolic functions |
Infinity, NaN, and classification#
There is no inf keyword. Construct float values using float("inf"),
float("-inf"), or float("nan"). Infinity spellings are case-insensitive,
accept surrounding whitespace, and support inf/infinity with an optional sign.
There are no math.INF or math.NAN constants.
| Function | Result |
|---|---|
is_nan(x) |
Whether float x is NaN |
is_inf(x) |
Whether float x is positive or negative infinity |
is_finite(x) |
Whether float x is neither infinity nor NaN |
These three functions require float inputs and return booleans. They are the
exception to the package's finite-input rule. Constructing infinity is supported;
passing it to arithmetic functions such as math.sin still raises an error.
Integers#
These take int or longint arguments of one matching kind (floats raise
TypeError) and return that kind. Overflow raises the kind's overflow error.
| Function | Result |
|---|---|
gcd(a,b) |
Greatest common divisor, never negative; gcd(0,0) is 0 |
lcm(a,b) |
Least common multiple, never negative; 0 when either is 0 |
is_even(n) / is_odd(n) |
Boolean |
div_floor(a,b) / div_ceil(a,b) |
Quotient rounded toward negative/positive infinity; zero divisor raises RangeError |
factorial(n) |
n!; negative n raises RangeError |
perm(n,k) / comb(n,k) |
Ordered/unordered selections of k from n; 0 when k > n; negative arguments raise RangeError |
comb divides out common factors at each step, so it succeeds whenever the
result fits: comb(longint(66), longint(33)) is 7219428434016265740.
Importing and passing functions#
Use takepkg std.math = calc; to call calc.min(...). Without an alias the name is
math. Repeated imports of the same package under the same alias are deduplicated.
Aliases refer to one immutable module namespace. Functions can be stored and called:
takepkg std.math;
func m{
smaller = math.min;
out(smaller(4,9));
}
The package source is built into the marslang executable, so running a program
does not require locating a separate library file.
Implementation#
The whole public API is Marslang: std/math.mars. That file checks
arity, matching numeric kinds, float-only inputs, finite inputs, and finite results,
and implements min/max/abs/clamp, signs, copysign, rounding (truncation via % 1.0,
floor, ceil, half-to-even), checked integer pow, hypot, log, and interpolation.
It imports two native packages written in Rust: rs.core
(std/rs/core.rs) to raise named errors and read a value's kind,
and rs.math (std/rs/math.rs) for the platform's float primitives:
sqrt, cbrt, exp, expm1, ln, log1p, log2, log10, trigonometric and
hyperbolic functions, atan2, float pow, and the float sign bit.
Approximate equality, adjacent-float operations, inverse hyperbolic functions, decimal/fraction, and the optional convenience functions from the expansion proposal remain future work. Package boundaries for statistics, random generation, complex numbers, and linear algebra remain unchanged.