math
std/math — numbers.
Written in Kite, like the rest of the standard library. Nothing here needs compiler support, which is the test a standard library should have to pass.
absminmaxclamptruncfloorceilroundround_totrunc_tosqrtpowmax_intmin_intchecked_addwrapping_addhypotlerpsignpietauln2explnpowfcbrtsincostanatanatan2asinacosdegreesradians
abs
pub fn abs(x: float) -> float
min
pub fn min(a: float, b: float) -> float
max
pub fn max(a: float, b: float) -> float
clamp
pub fn clamp(x: float, low: float, high: float) -> float
trunc
pub fn trunc(x: float) -> float
Truncation towards zero, which is what an as int cast does.
Not only the cast, though. Every float of magnitude 2⁵² or more is already a whole number, and most of them are past what an int holds, where the cast saturates: trunc(1e20) used to answer 9223372036854775808. Such a value is its own truncation, and so is an infinity or a NaN, so they are handed back untouched and only what fits goes through the cast.
floor
pub fn floor(x: float) -> float
Comparisons rather than t != x, which would be exact float equality and warn — rightly, since it is rarely what someone means.
ceil
pub fn ceil(x: float) -> float
round
pub fn round(x: float) -> float
Half away from zero, which is what most people mean by rounding.
Decided on the fraction itself, x - trunc(x), which is exact below 2⁵². The obvious floor(x + 0.5) is not: the addition rounds, so 0.49999999999999994 + 0.5 is 1.0 and the largest float below a half rounded up, and above 2⁵² the addition moved x to a neighbouring whole number.
round_to
pub fn round_to(x: float) -> int
A float as an int, rounded to nearest.
A bare x as int warns, and rightly: it truncates towards zero, which is almost never what code that measured something meant. Saying round_to is saying which rounding was intended, and is the escape hatch that makes keeping the warning worthwhile — without one, every program that has to produce an integer from a measurement has to ignore a warning to do it.
trunc_to
pub fn trunc_to(x: float) -> int
A float as an int, truncated towards zero — the cast, named.
Same purpose as [round_to]: the bare cast warns because it is usually a mistake, and a caller who means it says which rounding they meant.
sqrt
pub fn sqrt(x: float) -> float
The square root, correctly rounded. Zero and negatives answer zero; an infinity is its own root.
Written in Kite rather than reached for from the host: a host call is a boundary two runtimes have to agree about, and this one gives the same bits everywhere — the same bits IEEE 754 requires of a hardware square root.
The range is reduced first, and that is most of the function. x is written as m · 4ᵏ with m in [1, 4) — multiplying by 4 and by 2 is exact, so this costs nothing — and Newton runs on m, from a start within 25% of the answer, where six steps are more than the quadratic convergence needs. Starting from x itself and stopping on an absolute tolerance, as this once did, was right only between about 1e-8 and 1e10: sqrt(1e12) answered 1279996.5 and sqrt(1e-12) 1.28e-6.
Newton in floating point lands within one unit in the last place, and a quarter of the time on the wrong side of the halfway point. The last step settles it in integers, where nothing rounds — see [nearest_root].
pow
pub fn pow(base: float, exponent: int) -> float
base raised to a whole power. Negative powers give the reciprocal.
max_int
pub fn max_int() -> int
The largest int.
min_int
pub fn min_int() -> int
The smallest int. Written as a subtraction because 9223372036854775808 is not an int and so cannot be negated in source.
checked_add
pub fn checked_add(a: int, b: int) -> Option<int>
a + b, or nil when that does not fit.
The test is done by subtraction rather than by adding and looking at the result, because adding is what traps. max_int() - b is in range whenever b is positive, and min_int() - b is in range whenever b is negative, so neither side of the question can overflow while it is being asked.
wrapping_add
pub fn wrapping_add(a: int, b: int) -> int
a + b, wrapped into the range of an int — in every build.
On overflow the answer is a + b ∓ 2⁶⁴, and that is computed rather than discovered: with two positives too large, (a + min_int()) + (b + min_int()) is the same number and every step of it is in range, because min_int() is exactly -2⁶³ and shifting both operands down by it lands the sum in [min_int(), -2]. The negative case is the mirror image.
hypot
pub fn hypot(x: float, y: float) -> float
The length of the hypotenuse — the distance from the origin to (x, y).
sqrt(x * x + y * y) overflows to infinity once either side passes about 1e154, though the answer is nowhere near that large, and loses its precision to underflow below about 1e-154. So outside a comfortable range both sides are first scaled by a power of two — exact, so it costs no precision — and the answer is scaled back.
lerp
pub fn lerp(a: float, b: float, t: float) -> float
A point t of the way from a to b.
sign
pub fn sign(x: float) -> int
-1, 0 or 1.
pi
pub fn pi() -> float
The ratio of a circle's circumference to its diameter, to the precision a float holds.
e
pub fn e() -> float
tau
pub fn tau() -> float
ln2
pub fn ln2() -> float
exp
pub fn exp(x: float) -> float
e raised to x.
Reduced by x = k·ln2 + r, so the series only ever sees |r| ≤ ln2/2 and the rest is a power of two. Without that a series for exp(20) would need hundreds of terms and lose most of its precision to cancellation.
ln
pub fn ln(x: float) -> float
The natural logarithm. Zero and negatives have none; both answer zero, which is the same choice sqrt makes above.
Reduced to a mantissa in [√½, √2) so the series argument stays under 0.172 in magnitude. The series is the one for atanh, which converges twice as fast here as the direct series for ln(1 + s).
powf
pub fn powf(base: float, exponent: float) -> float
base raised to a float power, by exp(exponent · ln base).
Only defined for a non-negative base: a negative one raised to a fractional power is not a real number, and raised to a whole one is [pow], which is exact where this would be approximate. Naming the two separately is what keeps a caller from getting an approximation of something exact.
cbrt
pub fn cbrt(x: float) -> float
The cube root, keeping the sign — unlike powf, which cannot.
sin
pub fn sin(x: float) -> float
cos
pub fn cos(x: float) -> float
tan
pub fn tan(x: float) -> float
atan
pub fn atan(x: float) -> float
The arctangent, in radians, in (-π/2, π/2).
Twice reduced. atan(x) = π/2 − atan(1/x) brings anything past 1 inside; the addition formula then brings anything past tan(π/12) down to 0.2679, where the series loses a decimal digit per two terms. Applying the series directly at x = 1 — where it is Leibniz's series for π/4 — would need thousands of terms.
atan2
pub fn atan2(y: float, x: float) -> float
The angle of the point (x, y) from the positive x axis, in (-π, π].
The quadrant comes from the signs, which is the whole reason this exists separately from atan(y / x): that division throws away which quadrant the point was in, and (-1, -1) and (1, 1) are not the same direction.
asin
pub fn asin(x: float) -> float
acos
pub fn acos(x: float) -> float
degrees
pub fn degrees(radians: float) -> float
radians
pub fn radians(degrees: float) -> float