math
Trigonometry, number theory, statistics and number formatting, with the results and edge cases you will meet in real calculations.
import "std:math"std:math is for arithmetic that + - * / can't do: roots, powers, angles, primes, averages and spread. Reach for it when you are measuring, scaling, summarising a list of numbers or turning a number into text with a fixed number of decimals.
A few functions (floor, ceil, round, abs, min, max) are also built into the language and work without an import. The rest need import "std:math".
Roots, powers and rounding#
import "std:math"
log math.sqrt(16)
log math.pow(2, 10)
log math.hypot(3, 4)
log math.cbrt(27)
log math.round(2.5) math.floor(2.7) math.ceil(2.1) math.trunc(-2.7)round rounds halves away from zero. floor goes down, ceil goes up, and trunc drops the fraction, so it rounds toward zero. That matters for negative numbers: floor(-2.7) is -3, trunc(-2.7) is -2.
There is no integer division operator in OSL, so floor(a / b) is how you divide and drop the remainder. math.mod(a, b) gives the remainder, with the sign of a:
import "std:math"
log floor(17 / 5) math.mod(17, 5)
log math.mod(-7, 3)Constants#
math.pi, math.tau (two pi), math.e and math.phi (the golden ratio) are constants, not functions: no brackets.
import "std:math"
auto radius = 3
log math.pi * (radius ^ 2)
log math.tauAngles#
The trigonometric functions take radians. Convert with math.radians and math.degrees:
import "std:math"
log math.sin(math.radians(90))
log math.cos(0)
log math.degrees(math.pi)
log math.atan2(1, 1)atan2(y, x) is the angle of a point from the x axis, and unlike atan(y / x) it gets the quadrant right and doesn't divide by zero. math.hypot(x, y) is the distance from the origin.
Here is the distance between two points on a plane:
import "std:math"
def distance(number x1, number y1, number x2, number y2) number (
return math.hypot(x2 - x1, y2 - y1)
)
log distance(0, 0, 6, 8)
log distance(1, 1, 4, 5)Limiting and blending values#
clamp(value, min, max) keeps a value inside a range. lerp(start, end, t) moves between two values: t of 0 gives start, 1 gives end.
import "std:math"
log math.clamp(15, 0, 10)
log math.clamp(-5, 0, 10)
log math.lerp(0, 100, 0.25)
log math.lerp(10, 20, 0.5)
log math.sign(-4) math.sign(0)Together they make a progress bar: math.clamp(done / total, 0, 1) can never leave the 0 to 1 range, however wrong the inputs are.
Percentages and fixed decimals#
math.toPercent(part, total) gives the percentage. math.toFixed(x, digits) returns text with exactly that many decimals, which is what you want for display, since a number alone can't remember trailing zeros:
import "std:math"
auto pct = math.toPercent(1, 3)
log pct
log math.toFixed(pct, 1) ++ "%"
log math.toFixed(2, 3)Number theory#
gcd and lcm find the greatest common divisor and least common multiple. isPrime tests a number and primes(n) lists the first n primes:
import "std:math"
log math.gcd(12, 18)
log math.lcm(4, 6).unwrap()
log math.isPrime(97) math.isPrime(91)
log math.primes(8)lcm, factorial and fibonacci return a result, because the answer can outgrow an int:
import "std:math"
log math.factorial(10).unwrap()
log math.fibonacci(20).unwrap()
auto big = math.factorial(30)
log big.isErr() big.unwrapErr().kindA negative argument fails with a ValueError. Handle it as the errors lesson shows, with catch, switch, ! or unwrapOr.
Summarising a list#
The statistics functions take an array of numbers. sum and product can't fail (an empty array gives 0 and 1), so they return plain numbers:
import "std:math"
number[] scores = [72, 85, 90, 64, 85]
log math.sum(scores)
log math.product([2, 3, 4])The functions that need at least one number (avg, median, maxOf, minOf, rangeOf and the rest) return a result, which fails with a ValueError on an empty array:
import "std:math"
number[] scores = [72, 85, 90, 64, 85]
log math.avg(scores).unwrap()
log math.median(scores).unwrap()
log math.mode(scores)
log math.maxOf(scores).unwrap() math.minOf(scores).unwrap()
log math.rangeOf(scores).unwrap()
number[] none = []
auto e = math.avg(none).unwrapErr()
log e.kind ++ ": " ++ e.messagemode returns an array because several values can tie, and an empty array is simply an empty list of modes, so it is the one that doesn't fail. A friendlier average is one line:
import "std:math"
def average(number[] values) number (
return math.avg(values).unwrapOr(0)
)
log average([4, 8])
log average([])Spread and position#
variance and standardDeviation describe how far values lie from the mean. They treat the numbers as a whole population unless you pass {sample: true}, which divides by one less than the count:
import "std:math"
number[] data = [2, 4, 4, 4, 5, 5, 7, 9]
log math.variance(data).unwrap()
log math.standardDeviation(data).unwrap()
log math.standardDeviation(data, {sample: true}).unwrap()percentile(numbers, p) takes p from 0 to 100, quantile takes 0 to 1, and quartiles gives all three cut points at once:
import "std:math"
number[] times = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
log math.percentile(times, 90).unwrap()
log math.quartiles(times).unwrap()
log math.iqr(times).unwrap()zScores says how many standard deviations each value is from the mean, which makes outliers easy to find. normalize rescales to 0 to 1:
import "std:math"
log math.zScores([1, 2, 3])
log math.normalize([10, 20, 30])correlation and covariance compare two equally long arrays: math.correlation([1, 2, 3], [2, 4, 6]).unwrap() is 1, a perfect positive relationship.
NaN and infinity#
Some inputs have no real answer, and the result is NaN (not a number) instead of an error. NaN is never equal to anything, even itself, so test for it with a function:
import "std:math"
auto bad = math.sqrt(-1)
log bad
log math.isNaN(bad)
log math.isFinite(5) math.isFinite(bad)math.isInfinite tests for the infinities. Dividing by zero with / throws a MathError rather than returning infinity, so a NaN mostly comes from the math functions: sqrt, log, asin and acos outside their domains.
Example: grade report#
A real use pulls several of these together: summarise scores, format them, and guard the empty case.
import "std:math"
def report(string name, number[] scores) string (
if scores.len == 0 return name ++ ": no scores"
auto mean = math.avg(scores).unwrap()
auto spread = math.standardDeviation(scores).unwrap()
return name ++ ": mean " ++ math.toFixed(mean, 1) ++ ", spread " ++ math.toFixed(spread, 1)
)
log report("Ada", [90, 85, 100])
log report("Bo", [])What does this print?
auto a = math.sqrt(-1)
auto b = math.sqrt(-1)
log a == bMean and range
Print the average of the temperatures to one decimal place, then the gap between the hottest and coldest day.
19.8 8
API reference#
71 members, generated from the std:math source of OSL 9.3.0.
Functions
math.abs(number x) numberabs returns the absolute value of x.
math.acos(number x) numberacos returns the arccosine of x in radians, or NaN outside -1 to 1.
math.asin(number x) numberasin returns the arcsine of x in radians, or NaN outside -1 to 1.
math.atan(number x) numberatan returns the arctangent of x in radians.
math.atan2(number y, number x) numberatan2 returns the angle in radians from the positive x axis to the point (x, y), from -pi to pi. Note that y comes first.
math.avg(number[] numbers) result<number, error>avg returns the arithmetic mean of numbers. Fails with ValueError for an empty array.
math.bits(number x) intbits returns the IEEE 754 binary64 encoding of x, reinterpreted as a signed 64-bit integer. fromBits(bits(x)) is x, including NaN payloads and -0.
math.cbrt(number x) numbercbrt returns the cube root of x.
math.ceil(number x) numberceil rounds x up to the nearest whole number.
math.clamp(number value, number min, number max) numberclamp limits value to the range from min to max. The bounds may come in either order.
math.correlation(number[] a, number[] b) result<number, error>correlation returns the Pearson correlation of two equally long arrays of paired values, from -1 to 1. Fails with ValueError for empty arrays, arrays of different lengths, or an array whose values are all equal, which has no correlation.
math.cos(number x) numbercos returns the cosine of x radians.
math.cosh(number x) numbercosh returns the hyperbolic cosine of x.
math.covariance(number[] a, number[] b) result<number, error>covariance returns the population covariance of two equally long arrays of paired values. Fails with ValueError for empty arrays or arrays of different lengths.
math.degrees(number radians) numberdegrees converts radians to degrees.
math.exp(number x) numberexp returns e raised to the power x.
math.factorial(int n) result<int, error>factorial returns n! (1 * 2 * ... * n). Fails with ValueError for a negative n, and with OverflowError for one above 20, whose factorial doesn't fit an int.
math.fibonacci(int n) result<int, error>fibonacci returns the nth Fibonacci number, counting fibonacci(0) as 0 and fibonacci(1) as 1. Fails with ValueError for a negative n, and with OverflowError for one above 92, whose result doesn't fit an int.
math.floor(number x) numberfloor rounds x down to the nearest whole number.
math.fma(number x, number y, number z) numberfma returns x * y + z rounded once, as IEEE 754 fusedMultiplyAdd does.
math.fromBits(int bits) numberfromBits returns the number whose IEEE 754 binary64 encoding is bits.
math.fround(number x) numberfround matches JavaScript's Math.fround: the nearest float32 value, as a number.
math.gcd(int a, int b) intgcd returns the greatest common divisor of a and b, which is never negative; math.gcd(0, 0) is 0. The one result an int can't hold, 2^63 from the smallest int, wraps as int arithmetic does.
math.geometricMean(number[] numbers) result<number, error>geometricMean returns the nth root of the product of n numbers, which must all be above 0. Fails with ValueError for an empty array or a number that is 0 or less.
math.harmonicMean(number[] numbers) result<number, error>harmonicMean returns the count of numbers divided by the sum of their reciprocals; they must all be above 0. Fails with ValueError for an empty array or a number that is 0 or less.
math.hypot(number x, number y) numberhypot returns the length of the hypotenuse, sqrt(x*x + y*y), without overflowing for large values.
math.iqr(number[] numbers) result<number, error>iqr returns the interquartile range of numbers, q3 minus q1. Fails with ValueError for an empty array.
math.isFinite(number x) booleanisFinite reports whether x is neither infinite nor NaN.
math.isInfinite(number x) booleanisInfinite reports whether x is positive or negative infinity; use math.sign(x) for which one.
math.isNaN(number x) booleanisNaN reports whether x is NaN (not a number).
math.isPrime(number n) booleanisPrime reports whether n is a prime number. Numbers below 2 and numbers with a fractional part are not prime.
math.lcm(int a, int b) result<int, error>lcm returns the least common multiple of a and b, which is never negative, or 0 when either is 0. Fails with OverflowError when the result doesn't fit an int.
math.ldexp(number x, int exp) numberldexp returns x * 2^exp, rounding once even when the result is subnormal.
math.lerp(number start, number end, number t) numberlerp interpolates linearly from start to end: t of 0 gives start, 1 gives end, and values outside 0 to 1 extrapolate.
math.log(number x) numberlog returns the natural logarithm of x: NaN when x is negative and -Infinity when it is 0.
math.log10(number x) numberlog10 returns the base-10 logarithm of x.
math.log2(number x) numberlog2 returns the base-2 logarithm of x.
math.max(number a, number b) numbermax returns the larger of a and b.
math.maxOf(number[] numbers) result<number, error>maxOf returns the largest of numbers. Fails with ValueError for an empty array.
math.median(number[] numbers) result<number, error>median returns the middle value of numbers, or the mean of the two middle values for an even count. Fails with ValueError for an empty array.
math.min(number a, number b) numbermin returns the smaller of a and b.
math.minOf(number[] numbers) result<number, error>minOf returns the smallest of numbers. Fails with ValueError for an empty array.
math.mod(number a, number b) numbermod returns the remainder of a divided by b, with the sign of a: math.mod(-7, 3) is -1. Throws ValueError when b is 0.
math.mode(number[] numbers) number[]mode returns the most frequent values in numbers, in ascending order: one value usually, several on a tie, and none for an empty array.
math.normalize(number[] numbers) number[]normalize rescales numbers to the range 0 to 1, mapping the smallest to 0 and the largest to 1. When the numbers are all equal, each becomes 0.
math.percentile(number[] numbers, number p) result<number, error>percentile returns the pth percentile of numbers, for p from 0 to 100, interpolating between the closest values: the 50th is the median. Throws ValueError for p outside 0 to 100, and fails with ValueError for an empty array.
math.pow(number base, number exponent) numberpow returns base raised to the power exponent.
math.primes(int count) int[]primes returns the first count prime numbers, starting at 2. Throws ValueError for a negative count.
math.product(number[] numbers) numberproduct returns numbers multiplied together, or 1 for an empty array.
math.quantile(number[] numbers, number q) result<number, error>quantile returns the qth quantile of numbers, for q from 0 to 1, the same as math.percentile(numbers, q * 100). Throws ValueError for q outside 0 to 1, and fails with ValueError for an empty array.
math.quartiles(number[] numbers) result<{q1: number, q2: number, q3: number}, error>quartiles returns the 25th, 50th and 75th percentiles of numbers as {q1, q2, q3}. Fails with ValueError for an empty array.
math.radians(number degrees) numberradians converts degrees to radians.
math.rangeOf(number[] numbers) result<number, error>rangeOf returns the largest of numbers minus the smallest. Fails with ValueError for an empty array.
math.round(number x) numberround rounds x to the nearest whole number, with halves rounded away from zero: 2.5 is 3 and -2.5 is -3.
math.sign(number x) intsign returns 1 for a positive x, -1 for a negative one and 0 for 0 or NaN.
math.sin(number x) numbersin returns the sine of x radians.
math.sinh(number x) numbersinh returns the hyperbolic sine of x.
math.sqrt(number x) numbersqrt returns the square root of x, or NaN when x is negative.
math.standardDeviation(number[] numbers, object? options) result<number, error>standardDeviation returns the population standard deviation of numbers, the square root of math.variance. With the option sample: true it returns the sample standard deviation instead. Fails with ValueError for an empty array, or fewer than 2 numbers for a sample.
math.sum(number[] numbers) numbersum returns the total of numbers, or 0 for an empty array.
math.tan(number x) numbertan returns the tangent of x radians.
math.tanh(number x) numbertanh returns the hyperbolic tangent of x.
math.toFixed(number x, int digits) stringtoFixed formats x with exactly digits digits after the decimal point, as C's printf("%.*f") does: the exact binary value of x is rounded to the nearest, with exact halves rounded to even, so math.toFixed(2.5, 0) is "2" and math.toFixed(0.125, 2) is "0.12". NaN and the infinities format as "NaN", "+Inf" and "-Inf". Throws ValueError for digits outside 0 to 100.
math.toPercent(number x, number total) numbertoPercent returns x as a percentage of total: math.toPercent(25, 200) is 12.5. Throws ValueError when total is 0.
math.trunc(number x) numbertrunc drops the fractional part of x, rounding toward zero.
math.variance(number[] numbers, object? options) result<number, error>variance returns the population variance of numbers: the mean squared difference from their mean. With the option sample: true it returns the sample variance instead, dividing by one less than the count. Fails with ValueError for an empty array, or fewer than 2 numbers for a sample.
math.zScores(number[] numbers) number[]zScores returns how many population standard deviations each of numbers is from their mean. When the numbers are all equal, every score is 0.
Constants
number math.eE is Euler's number, the base of the natural logarithm, 2.718281828459045.
number math.phiPhi is the golden ratio, 1.618033988749895.
number math.piPi is the ratio of a circle's circumference to its diameter, 3.141592653589793.
number math.tauTau is a full turn in radians, 2 * pi.