Math Library
While the arithmetic and logic operators represent the basic operations that our [[CPU]] can perform, there are many other common math functions that com in handy. Since they are so common, programming languages usually have a math library that provides these functions. Logarithms, trigonometry and random number generation are just of few of the types of functions typically provided.
Math Constants
Math constants provide commonly used mathematical constanst to the highest precesion available. Some of the more useful math constants are summarized below.
| Constant | Description |
|---|---|
| exp(1.0) | Euler's constant [[ℯ]], base of the natural logarithm |
| Double.pi | [[π]], Ratio of a circle's circumference to its diameter |
Math Functions
These most useful math functions are summarized below.
| Function | Description |
|---|---|
| acos(x) | [[Arc cosine]] of x, result is in the range [0,π] [[Radians]] |
| acosh(x) | [[Arc hyperbolic cosine]] of x |
| asin(x) | [[Arc sine]] of x, result is in the range [-π/2,π/2] [[Radians]] |
| asinh(x) | [[Arc hyperbolic sine]] of x |
| atan(x) | [[Arc tangent]] of x, result is in the range [-π/2,π/2] [[Radians]] |
| atan2(y,x) | Angle θ from the conversion of [[rectangular coordinates]] (x,y), result is in the range [-π,π] [[Radians]] |
| atanh(x) | [[Arc hyperbolic tangent]] of x |
| ceil(x) | Smallest integer value greater than or equal to x |
| cos(x) | [[Cosine]] of x (in [[Radians]]) |
| cosh(x) | [[Hyperbolic cosine]] of x |
| exp(x) | [[ℯ]] rasied to the power x, i.e. ℯx |
| fabs(x) | [[Absolute value]] of x |
| floor(x) | Largest integer less than x |
| fmax(x,y) | Larger of x and y |
| fmin(x,y) | Smaller of x and y |
| log(x) | [[Natural logarithm]] of x |
| log10(x) | [[Common logarithm]] of x |
| pow(x,y) | x raised to the power y, i.e. xy |
| Double.random(in: 0.0 ..< 1.0) | [[Pseudorandom]] number on the interval [0, 1) |
| sin(x) | [[Sine]] of x (in [[Radians]]) |
| sinh(x) | [[Hyperbolic sine]] of x |
| sqrt(x) | [[Square root]] of x |
| tan(x) | [[Tangent]] of x (in [[Radians]]) |
| tanh(x) | [[Hyperbolic tangent]] of x |
Be sure to add the following import to the top of your program in order to use these math functions and constants.
import Foundation
The program below illustrates the use of the floating point math functions.
#!/usr/bin/env swift;
/******************************************************************************
* This program demonstrates the math library.
*
* Copyright © 2016 Richard Lesh. All rights reserved.
*****************************************************************************/
import Foundation
import Utils
func main() -> Void {
let a:Double = Double.pi / Double(6)
let b:Double = Double.pi / Double(4)
let c:Double = -a * 2
let d:Double = -b * 2
let e:Double = M_E
print(Utils.format("pi = {0:f}", Double.pi))
print(Utils.format("e = {0:f}", M_E))
// abs, floor, ceil, round, trunc, min, max
print(Utils.format("abs({0:f}) = {1:f}", a, fabs(a)))
print(Utils.format("abs({0:f}) = {1:f}", c, fabs(c)))
print(Utils.format("floor({0:f}) = {1:f}", a, floor(a)))
print(Utils.format("floor({0:f}) = {1:f}", c, floor(c)))
print(Utils.format("ceil({0:f}) = {1:f}", a, ceil(a)))
print(Utils.format("ceil({0:f}) = {1:f}", c, ceil(c)))
print(Utils.format("round({0:f}) = {1:f}", a, round(a)))
print(Utils.format("round({0:f}) = {1:f}", c, round(c)))
print(Utils.format("trunc({0:f}) = {1:f}", a, trunc(a)))
print(Utils.format("trunc({0:f}) = {1:f}", c, trunc(c)))
print(Utils.format("min({0:f}, {1:f}) = {2:f}", a, c, fmin(a, c)))
print(Utils.format("max({0:f}, {1:f}) = {2:f}", a, c, fmax(a, c)))
// sin, cos, tan, atan, atan2, acos, asin
print(Utils.format("sin({0:f}) = {1:f}", a, sin(a)))
print(Utils.format("sin({0:f}) = {1:f}", b, sin(b)))
print(Utils.format("sin({0:f}) = {1:f}", c, sin(c)))
print(Utils.format("sin({0:f}) = {1:f}", d, sin(d)))
print(Utils.format("cos({0:f}) = {1:f}", a, cos(a)))
print(Utils.format("cos({0:f}) = {1:f}", b, cos(b)))
print(Utils.format("cos({0:f}) = {1:f}", c, cos(c)))
print(Utils.format("cos({0:f}) = {1:f}", d, cos(d)))
print(Utils.format("tan({0:f}) = {1:f}", a, tan(a)))
print(Utils.format("tan({0:f}) = {1:f}", b, tan(b)))
print(Utils.format("tan({0:f}) = {1:f}", c, tan(c)))
print(Utils.format("asin({0:f}) = {1:f}", sin(a), asin(sin(a))))
print(Utils.format("asin({0:f}) = {1:f}", sin(b), asin(sin(b))))
print(Utils.format("asin({0:f}) = {1:f}", sin(c), asin(sin(c))))
print(Utils.format("asin({0:f}) = {1:f}", sin(d), asin(sin(d))))
print(Utils.format("acos({0:f}) = {1:f}", cos(a), acos(cos(a))))
print(Utils.format("acos({0:f}) = {1:f}", cos(b), acos(cos(b))))
print(Utils.format("acos({0:f}) = {1:f}", cos(c), acos(cos(c))))
print(Utils.format("acos({0:f}) = {1:f}", cos(d), acos(cos(d))))
print(Utils.format("atan({0:f}) = {1:f}", tan(a), atan(tan(a))))
print(Utils.format("atan({0:f}) = {1:f}", tan(b), atan(tan(b))))
print(Utils.format("atan({0:f}) = {1:f}", tan(c), atan(tan(c))))
// 45 degrees
print(Utils.format("atan2({0:f}, {1:f}) = {2:f}", 1.0, 1.0, atan2(1.0, 1.0)))
// 30 degrees
print(Utils.format("atan2({0:f}, {1:f}) = {2:f}", 1.0, sqrt(3.0), atan2(1.0, sqrt(3.0))))
// sinh, cosh, tanh, atanh, acosh, asinh
print(Utils.format("sinh({0:f}) = {1:f}", a, sinh(a)))
print(Utils.format("sinh({0:f}) = {1:f}", b, sinh(b)))
print(Utils.format("sinh({0:f}) = {1:f}", c, sinh(c)))
print(Utils.format("sinh({0:f}) = {1:f}", d, sinh(d)))
print(Utils.format("cosh({0:f}) = {1:f}", a, cosh(a)))
print(Utils.format("cosh({0:f}) = {1:f}", b, cosh(b)))
print(Utils.format("cosh({0:f}) = {1:f}", c, cosh(c)))
print(Utils.format("cosh({0:f}) = {1:f}", d, cosh(d)))
print(Utils.format("tanh({0:f}) = {1:f}", a, tanh(a)))
print(Utils.format("tanh({0:f}) = {1:f}", b, tanh(b)))
print(Utils.format("tanh({0:f}) = {1:f}", c, tanh(c)))
print(Utils.format("tanh({0:f}) = {1:f}", d, tanh(d)))
print(Utils.format("asinh({0:f}) = {1:f}", sinh(a), asinh(sinh(a))))
print(Utils.format("asinh({0:f}) = {1:f}", sinh(b), asinh(sinh(b))))
print(Utils.format("asinh({0:f}) = {1:f}", sinh(c), asinh(sinh(c))))
print(Utils.format("asinh({0:f}) = {1:f}", sinh(d), asinh(sinh(d))))
print(Utils.format("acosh({0:f}) = {1:f}", cosh(a), acosh(cosh(a))))
print(Utils.format("acosh({0:f}) = {1:f}", cosh(b), acosh(cosh(b))))
print(Utils.format("acosh({0:f}) = {1:f}", cosh(c), acosh(cosh(c))))
print(Utils.format("acosh({0:f}) = {1:f}", cosh(d), acosh(cosh(d))))
print(Utils.format("atanh({0:f}) = {1:f}", tanh(a), atanh(tanh(a))))
print(Utils.format("atanh({0:f}) = {1:f}", tanh(b), atanh(tanh(b))))
print(Utils.format("atanh({0:f}) = {1:f}", tanh(c), atanh(tanh(c))))
print(Utils.format("atanh({0:f}) = {1:f}", tanh(d), atanh(tanh(d))))
// log, log10, exp, pow, sqrt
print(Utils.format("log({0:f}) = {1:f}", a, log(a)))
print(Utils.format("log({0:f}) = {1:f}", b, log(b)))
print(Utils.format("log({0:f}) = {1:f}", -c, log(-c)))
print(Utils.format("log({0:f}) = {1:f}", -d, log(-d)))
print(Utils.format("log({0:f}) = {1:f}", e, log(e)))
print(Utils.format("log10({0:f}) = {1:f}", a, log10(a)))
print(Utils.format("log10({0:f}) = {1:f}", b, log10(b)))
print(Utils.format("log10({0:f}) = {1:f}", -c, log10(-c)))
print(Utils.format("log10({0:f}) = {1:f}", -d, log10(-d)))
print(Utils.format("log10({0:f}) = {1:f}", e, log10(e)))
print(Utils.format("exp({0:f}) = {1:f}", 0.5, exp(0.5)))
print(Utils.format("exp({0:f}) = {1:f}", 1.0, exp(1.0)))
print(Utils.format("exp({0:f}) = {1:f}", 2.0, exp(2.0)))
print(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 0.5, pow(10.0, 0.5)))
print(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 1.0, pow(10.0, 1.0)))
print(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 2.0, pow(10.0, 2.0)))
print(Utils.format("sqrt({0:f}) = {1:f}", 0.5, sqrt(0.5)))
print(Utils.format("sqrt({0:f}) = {1:f}", 2.0, sqrt(2.0)))
print(Utils.format("sqrt({0:f}) = {1:f}", 10.0, sqrt(10.0)))
// random numbers
print(Utils.format("random() = {0:f}", Double.random(in: 0.0 ..< 1.0)))
print(Utils.format("random() = {0:f}", Double.random(in: 0.0 ..< 1.0)))
print(Utils.format("random() = {0:f}", Double.random(in: 0.0 ..< 1.0)))
exit(EXIT_SUCCESS)
}
main()
Output
The program below illustrates the use of the integer math and random number functions.
#!/usr/bin/env swift;
/******************************************************************************
* This program demonstrates the math integer functions.
*
* Copyright © 2020 Richard Lesh. All rights reserved.
*****************************************************************************/
import Foundation
import Utils
func main() -> Void {
let a:Int = 5
let b:Int = 10
let c:Int = -2
// abs, floor, ceil, round, trunc, min, max
print(Utils.format("abs({0:d}) = {1:d}", a, abs(a)))
print(Utils.format("abs({0:d}) = {1:d}", c, abs(c)))
print(Utils.format("min({0:d}, {1:d}) = {2:d}", a, b, min(a, b)))
print(Utils.format("max({0:d}, {1:d}) = {2:d}", a, b, max(a, b)))
print(Utils.format("min({0:d}, {1:d}) = {2:d}", b, c, min(b, c)))
print(Utils.format("max({0:d}, {1:d}) = {2:d}", b, c, max(b, c)))
// random numbers
print(Utils.format("random({0:d}) = {1:d}", a, Int.random(in: 0..<a)))
print(Utils.format("random({0:d}) = {1:d}", a, Int.random(in: 0..<a)))
print(Utils.format("random({0:d}) = {1:d}", a, Int.random(in: 0..<a)))
print(Utils.format("random({0:d}) = {1:d}", a, Int.random(in: 0..<a)))
print(Utils.format("random({0:d}) = {1:d}", a, Int.random(in: 0..<a)))
print(Utils.format("random({0:d}) = {1:d}", b, Int.random(in: 0..<b)))
print(Utils.format("random({0:d}) = {1:d}", b, Int.random(in: 0..<b)))
print(Utils.format("random({0:d}) = {1:d}", b, Int.random(in: 0..<b)))
print(Utils.format("random({0:d}) = {1:d}", b, Int.random(in: 0..<b)))
print(Utils.format("random({0:d}) = {1:d}", b, Int.random(in: 0..<b)))
print(Utils.format("random(2) = {0:d}", Int.random(in: 0..<2)))
print(Utils.format("random(2) = {0:d}", Int.random(in: 0..<2)))
print(Utils.format("random(2) = {0:d}", Int.random(in: 0..<2)))
print(Utils.format("random(2) = {0:d}", Int.random(in: 0..<2)))
print(Utils.format("random(2) = {0:d}", Int.random(in: 0..<2)))
print(Utils.format("random() = {0:f}", Double.random(in: 0.0 ..< 1.0)))
print(Utils.format("random() = {0:f}", Double.random(in: 0.0 ..< 1.0)))
print(Utils.format("random() = {0:f}", Double.random(in: 0.0 ..< 1.0)))
print(Utils.format("random() = {0:f}", Double.random(in: 0.0 ..< 1.0)))
print(Utils.format("random() = {0:f}", Double.random(in: 0.0 ..< 1.0)))
exit(EXIT_SUCCESS)
}
main()
Output
Random Numbers
Random number generation is an important technique needed for simulations and games. Computers can't actually generate true random numbers, so we have to settle for [[pseudorandom]] numbers, i.e. numbers generated deterministically but hopefully in an unpredictable manner.
In modern Swift, random number generation is usually done with the standard library using functions such as Int.random(in:), Double.random(in:), and random number generators that conform to RandomNumberGenerator.
For the three most common cases of uniform integers, uniform floating point numbers, and normally distributed ([[Gaussian]]) floating point numbers, Swift commonly uses:
- uniform integers →
Int.random(in:) - uniform floating point numbers →
Double.random(in:) - normal (Gaussian) floating point numbers → a helper function such as the [[Box-Muller transform]]
For our example program we generate 10 numbers from each of the three distributions. Notice how each time we run the program, we will usually get different values.
import Foundation
func randomGaussian() -> Double {
var u1 = 0.0
var u2 = 0.0
// Avoid log(0)
repeat {
u1 = Double.random(in: 0.0 ..< 1.0)
} while u1 == 0.0
u2 = Double.random(in: 0.0 ..< 1.0)
return sqrt(-2.0 * log(u1)) * cos(2.0 * Double.pi * u2)
}
print("Uniform integers in [1, 6]")
for _ in 0..<10 {
print(Int.random(in: 1...6))
}
print("Uniform doubles in [0.0, 1.0)")
for _ in 0..<10 {
print(Double.random(in: 0.0 ..< 1.0))
}
print("Standard Normal")
for _ in 0..<10 {
print(randomGaussian())
}
Output
The uniform integer generator can produce integers uniformly in a range such as: [1, 6].
In Swift, integer bounds are often expressed with a closed range or a half-open range. So to simulate a six-sided die we could write:
Int.random(in: 1...6).
This means both endpoints are included, so the possible values are 1 through 6. That makes it perfect for dice rolls, random indices, and similar cases.
The uniform floating point generator produces values uniformly in the range: [0.0, 1.0).
In Swift, a common way to generate such a value is:
Double.random(in: 0.0 ..< 1.0).
This means that only the low endpoint 0.0 is included. The high endpoint 1.0 will not be generated, i.e. low <= random < high. You can scale this output to another range [low, high) with the function Double.random(in: low ..< high)
That is commonly used for probabilities, simulation, [[Monte Carlo Method]], and scaling into another range.
Swift does not provide a built-in standard normal random number function directly in the core standard library. To generate values from a normal distribution with mean = 0.0 and standard deviation = 1.0, we usually write a helper function based on the [[Box-Muller transform]].
That produces values from the standard normal distribution.
Most values cluster near the mean, and larger positive or negative values become less likely.
For example, to model exam scores centered around 75 with a standard deviation of 10, we can scale and shift the standard normal value like this:
75.0 + 10.0 * randomGaussian().
Deterministic vs Non-Deterministic Seeding
If you want the same random sequence every run, use a deterministic random number generator with a fixed seed. This is useful for debugging and testing.
By default, Swift’s built-in random functions such as Int.random(in:) and Double.random(in:) use a system-provided generator and do not expose a simple seed parameter.
If you want variation between runs, the default generator is appropriate.
Whichever technique you choose, only initialize the generator once. Do not recreate and reseed it repeatedly in a loop.
Using a Custom Random Number Generator
Swift also supports custom generators that conform to RandomNumberGenerator.
This is useful when you want deterministic sequences for testing or reproducible simulations.
struct MyGenerator: RandomNumberGenerator {
var state: UInt64 = 12345
mutating func next() -> UInt64 {
state = state &* 6364136223846793005 &+ 1
return state
}
}
var rng = MyGenerator()
let dieRoll = Int.random(in: 1...6, using: &rng)
let x = Double.random(in: 10.0 ..< 20.0, using: &rng)
This lets you generate repeatable sequences because the generator starts from a known initial state.
Why not use helper code everywhere?
Swift’s built-in random support is already quite strong for common cases:
- it directly supports integer ranges
- it directly supports floating point ranges
- it supports pluggable random number generators
- it integrates cleanly with the language’s range syntax
However, Gaussian values still usually require a helper function or an external library, since the core random APIs focus mainly on uniform distributions.
For quick one-line examples, Int.random(in:) and Double.random(in:) are excellent. For serious simulation, games, testing, or reusable code, custom generators and helper functions are often the better tools.
Questions
- {{Write an expression that yields √5.}}
- {{Write an expression that yields 3√5.}}
- {{Write an expression that yields the secant of π/4.}}
- {{Write an expression that yields log16 100.}}
Projects
More ★'s indicate higher difficulty level.
References
- [[Swift Community]]
- [[Swift Language Guide]]
- [[Swift Language Reference]]
- [[Swift Programming Language]], Apple Inc.
- [[Swift Doc]]
- [[We Heart Swift]]
- [[Swift Cookbook]]
- [[Swift Playground]]
- [[Swift at TutorialsPoint]]
- [[Hacking with Swift]]
Pure Programmer


