Skip to content

Math ​

Using it ​

std.math holds the integer helpers and the mathematical constants. A function of a float is not in the module: it is a method of f64, written on the value as Rust writes it, so a square root is x.sqrt(), a power is x.powi(n) or x.powf(y), and a limit such as the largest f64 is a static on the type, f64.max(). A program imports what it uses from the module by name:

talor
use std.math.{PI, gcd};

fn main() {
    println(`${gcd(12, 18)}`);      // 6: a function of the module
    println(`${PI}`);               // 3.14159: a constant of the module
    println(`${2.0.sqrt()}`);       // 1.41421: a method of f64
}

Interpolation writes a float with six significant digits, which is why PI prints as 3.14159; std.fmt writes more when the text matters (see Strings).

Integers ​

Every helper takes and answers i64, except the two predicates, which answer a bool.

FunctionWhat it answers
abs(x: i64): i64the magnitude
sign(x: i64): i64-1, 0 or 1
min(a: i64, b: i64): i64the smaller
max(a: i64, b: i64): i64the larger
clamp(x: i64, lo: i64, hi: i64): i64lo below lo, hi above hi, x between them
pow(base: i64, exp: i64): i64base multiplied by itself exp times; pow(0, 0) is 1, and a negative exp answers 0
gcd(a: i64, b: i64): i64the greatest common divisor, never negative: gcd(-4, 6) is 2, gcd(0, 5) is 5 and gcd(0, 0) is 0
lcm(a: i64, b: i64): i64the least common multiple, never negative, and 0 when either side is 0
is_even(x: i64): boolwhether x is even, negatives included: is_even(-4) is true
is_odd(x: i64): boolwhether x is odd: is_odd(-3) is true

An answer past i64 overflows as integer arithmetic does (Types): a panic with integer overflow, and a wrap in a build with --release. The smallest i64, -9223372036854775808, has no magnitude that fits, so abs and gcd of it panic; so do pow(2, 63) and lcm(9223372036854775807, 2). Under --release, abs of the smallest i64 answers it unchanged.

Constants ​

ConstantValueWhat it is
PI3.1415926535897931the ratio of a circle's circumference to its diameter
TAU6.2831853071795862the full turn, 2 * PI
E2.7182818284590451Euler's number, the base of ln
SQRT_21.4142135623730951the square root of 2
FRAC_1_SQRT_20.707106781186547571 / SQRT_2
LN_20.69314718055994529the natural logarithm of 2
LN_102.3025850929940459the natural logarithm of 10
LOG2_E1.4426950408889634the base-2 logarithm of E
LOG10_E0.43429448190325182the base-10 logarithm of E
FRAC_PI_21.5707963267948966PI / 2, a right angle
FRAC_PI_40.78539816339744828PI / 4

Each is the f64 nearest the real number, written to 17 significant digits, which is enough to name that double and no other. fmt.shortest(PI) writes the shortest text that reads back as the same double, 3.141592653589793.

The methods of f64 ​

Every method answers an f64 except the five predicates, which answer a bool, and every argument is an f64 except powi's, which is an i64. The names are Rust's, so the natural logarithm is ln and log takes its base. x is the receiver.

GroupMethods
Roots and powersx.sqrt(), x.cbrt(), x.powf(y) for a real exponent, x.powi(n) for an i64 exponent, negative allowed, x.hypot(y)
Exponentials and logarithmsx.exp(), x.exp2(), x.exp_m1(), x.ln() for the natural logarithm, x.log2(), x.log10(), x.ln_1p(), x.log(base)
Roundingx.floor(), x.ceil(), x.trunc() toward zero, x.round() with a half rounding away from zero, x.fract()
Trigonometry, in radiansx.sin(), x.cos(), x.tan(), x.asin(), x.acos(), x.atan(), y.atan2(x) with the receiver as y, x.to_degrees(), x.to_radians()
Hyperbolicx.sinh(), x.cosh(), x.tanh(), x.asinh(), x.acosh(), x.atanh()
Sign and arithmeticx.abs(), x.signum(), x.copysign(s), x.recip(), x.mul_add(a, b) for x * a + b with one rounding
Comparisonx.min(y), x.max(y), x.clamp(lo, hi)
Classificationx.is_nan(), x.is_infinite(), x.is_finite(), x.is_sign_negative(), x.is_sign_positive()
Limits, on the typef64.max(), f64.min_positive(), f64.epsilon(), f64.infinity(), f64.neg_infinity(), f64.nan()

f64.max() is the largest finite value, 1.7976931348623157e+308; f64.min_positive() is the smallest normal one, 2.2250738585072014e-308; and f64.epsilon() is the gap between 1.0 and the next double, 2.220446049250313e-16. The limits are calls on the type because a constant holds a literal, and no literal spells an infinity or a NaN.

What a float answers at its edges ​

No method panics. A method answers what IEEE 754 and the platform's C math library answer: (-1.0).sqrt() and 2.0.asin() are NaN, 0.0.ln() is -inf, and 0.0.powi(-1) and 1.0.atanh() are inf. Division answers too: 1.0 / 0.0 is inf, -1.0 / 0.0 is -inf and 0.0 / 0.0 is NaN, where an integer division by zero panics.

A NaN equals nothing, itself included. x == x is false for a NaN and x != x is true, and <, >, <= and >= are all false when either side is NaN, so a program asks x.is_nan(). x.min(y) and x.max(y) answer the number when the other side is NaN, so f64.nan().max(1.0) is 1.0. x.clamp(lo, hi) answers NaN for a NaN x, takes a NaN bound as no bound, and answers hi when lo is above hi.

round takes a half away from zero: 2.5.round() is 3.0, (-2.5).round() is -3.0 and 0.5.round() is 1.0. trunc goes toward zero, floor down and ceil up, and fract keeps the sign of x: (-2.75).fract() is -0.75.

Zero has a sign. -0.0 == 0.0 is true, and the two differ in the sign bit: (-0.0).is_sign_negative() is true, (-0.0).signum() is -1.0, and (-0.0).abs() is 0.0.

Compare within a tolerance. A float is the double nearest the real number, so arithmetic on two of them rounds: 0.1 + 0.2 == 0.3 is false. A test compares a computed float with std.testing.assert_near_f64, which takes the value, the expected value, the tolerance and a description, and fails on a NaN. An exact comparison is right where the answer is exact, as it is for the rounding methods and for sqrt of a perfect square: 9.0.sqrt() == 3.0 is true.

A method on a negative literal goes in parentheses. 2.0.sqrt() is the square root of 2.0, but -2.5.floor() negates 2.5.floor() and is -2.0, where (-2.5).floor() is -3.0.

Samples ​

A circle and a triangle ​

talor
use std.math.{PI, TAU};

fn circle_area(r: f64): f64 {
    PI * r.powi(2)
}

fn main() {
    let r = 3.0;
    println(`radius ${r}: area ${circle_area(r)}, circumference ${TAU * r}`);
    let a = 5.0;
    let b = 12.0;
    println(`legs ${a} and ${b}: hypotenuse ${a.hypot(b)}`);
}
radius 3: area 28.2743, circumference 18.8496
legs 5 and 12: hypotenuse 13

Rounding a price ​

as i64 drops the fraction, so a price that has no exact binary form loses a cent unless it is rounded first.

talor
fn main() {
    let price = 1.15;
    let scaled = price * 100.0;        // 114.99999999999999: 1.15 has no exact binary form
    println(`${scaled as i64} cents truncated, ${scaled.round() as i64} rounded`);
    let total = 7.0 * price;
    println(`${total.floor()} whole and ${(total.fract() * 100.0).round()} cents`);
}
114 cents truncated, 115 rounded
8 whole and 5 cents

Angles ​

The trigonometric methods take radians. y.atan2(x) is the angle of the point (x, y), so its receiver is y.

talor
fn main() {
    let angle = 30.0;
    println(`sin of ${angle} degrees: ${angle.to_radians().sin()}`);
    // The direction of the point (-1, 1) seen from the origin.
    let x = -1.0;
    let y = 1.0;
    println(`the point (${x}, ${y}) lies at ${y.atan2(x).to_degrees()} degrees`);
}
sin of 30 degrees: 0.5
the point (-1, 1) lies at 135 degrees

Reducing a fraction ​

talor
use std.math.{gcd, lcm};

fn main() {
    let num = 42;
    let den = 56;
    let g = gcd(num, den);
    println(`${num}/${den} reduces to ${num / g}/${den / g}`);
    // 1/4 + 1/6 over the smallest common denominator.
    let d = lcm(4, 6);
    println(`1/4 + 1/6 = ${d / 4 + d / 6}/${d}`);
}
42/56 reduces to 3/4
1/4 + 1/6 = 5/12

Testing for NaN ​

talor
fn describe(x: f64): string {
    if x.is_nan() {
        "not a number"
    } else if x.is_infinite() {
        "infinite"
    } else {
        `${x}`
    }
}

fn main() {
    let zero = 0.0;
    println(describe(1.0 / 4.0));
    println(describe(1.0 / zero));
    println(describe(zero / zero));
    println(describe((-1.0).sqrt()));
    let nan = f64.nan();
    println(`${nan == nan} ${nan != nan} ${nan.max(1.0)}`);
}
0.25
infinite
not a number
not a number
false true 1

Talor v0.1.0 - Released under the MIT OR Apache-2.0 license.