Double precision (64-bit) floating-point numbers in IEEE 754 representation.
This module contains common floating-point constants and utility functions.
Notation for special values in the documentation below:
+inf
: Positive infinity
-inf
: Negative infinity
NaN
: "not a number" (can have different sign bit values, but NaN != NaN
regardless of the sign).
Note: Floating point numbers have limited precision and operations may inherently result in numerical errors.
Examples of numerical errors:
0.1 + 0.1 + 0.1 == 0.3 // => false
1e16 + 1.0 != 1e16 // => false
(and many more cases)
Advice:
==
or !=
are discouraged. Instead, it is better to compare
floating-point numbers with a numerical tolerance, called epsilon.Example:
import Float "mo:base/Float";
let x = 0.1 + 0.1 + 0.1;
let y = 0.3;
let epsilon = 1e-6; // This depends on the application case (needs a numerical error analysis).
Float.equalWithin(x, y, epsilon) // => true
NaN sign:
abs
, neg
, and copySign
. Other operations can have an arbitrary
sign bit for NaN results.64-bit floating point number type.
public let pi : Float
Ratio of the circumference of a circle to its diameter. Note: Limited precision.
public let e : Float
Base of the natural logarithm. Note: Limited precision.
public func isNaN(number : Float) : Bool
Determines whether the number
is a NaN
("not a number" in the floating point representation).
Notes:
NaN
with itself or another number is always false
.NaN
value representations, such as positive and negative NaN,
signalling and quiet NaNs, each with many different bit representations.Example:
import Float "mo:base/Float";
Float.isNaN(0.0/0.0) // => true
public let abs : (x : Float) -> Float
Returns the absolute value of x
.
Special cases:
abs(+inf) => +inf
abs(-inf) => +inf
abs(-NaN) => +NaN
abs(-0.0) => 0.0
Example:
import Float "mo:base/Float";
Float.abs(-1.2) // => 1.2
public let sqrt : (x : Float) -> Float
Returns the square root of x
.
Special cases:
sqrt(+inf) => +inf
sqrt(-0.0) => -0.0
sqrt(x) => NaN if x < 0.0
sqrt(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.sqrt(6.25) // => 2.5
public let ceil : (x : Float) -> Float
Returns the smallest integral float greater than or equal to x
.
Special cases:
ceil(+inf) => +inf
ceil(-inf) => -inf
ceil(NaN) => NaN
ceil(0.0) => 0.0
ceil(-0.0) => -0.0
Example:
import Float "mo:base/Float";
Float.ceil(1.2) // => 2.0
public let floor : (x : Float) -> Float
Returns the largest integral float less than or equal to x
.
Special cases:
floor(+inf) => +inf
floor(-inf) => -inf
floor(NaN) => NaN
floor(0.0) => 0.0
floor(-0.0) => -0.0
Example:
import Float "mo:base/Float";
Float.floor(1.2) // => 1.0
public let trunc : (x : Float) -> Float
Returns the nearest integral float not greater in magnitude than x
.
This is equivalent to returning x
with truncating its decimal places.
Special cases:
trunc(+inf) => +inf
trunc(-inf) => -inf
trunc(NaN) => NaN
trunc(0.0) => 0.0
trunc(-0.0) => -0.0
Example:
import Float "mo:base/Float";
Float.trunc(2.75) // => 2.0
public let nearest : (x : Float) -> Float
Returns the nearest integral float to x
.
A decimal place of exactly .5 is rounded up for x > 0
and rounded down for x < 0
Special cases:
nearest(+inf) => +inf
nearest(-inf) => -inf
nearest(NaN) => NaN
nearest(0.0) => 0.0
nearest(-0.0) => -0.0
Example:
import Float "mo:base/Float";
Float.nearest(2.75) // => 3.0
public let copySign : (x : Float, y : Float) -> Float
Returns x
if x
and y
have same sign, otherwise x
with negated sign.
The sign bit of zero, infinity, and NaN
is considered.
Example:
import Float "mo:base/Float";
Float.copySign(1.2, -2.3) // => -1.2
public let min : (x : Float, y : Float) -> Float
Returns the smaller value of x
and y
.
Special cases:
min(NaN, y) => NaN for any Float y
min(x, NaN) => NaN for any Float x
Example:
import Float "mo:base/Float";
Float.min(1.2, -2.3) // => -2.3 (with numerical imprecision)
public let max : (x : Float, y : Float) -> Float
Returns the larger value of x
and y
.
Special cases:
max(NaN, y) => NaN for any Float y
max(x, NaN) => NaN for any Float x
Example:
import Float "mo:base/Float";
Float.max(1.2, -2.3) // => 1.2
public let sin : (x : Float) -> Float
Returns the sine of the radian angle x
.
Special cases:
sin(+inf) => NaN
sin(-inf) => NaN
sin(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.sin(Float.pi / 2) // => 1.0
public let cos : (x : Float) -> Float
Returns the cosine of the radian angle x
.
Special cases:
cos(+inf) => NaN
cos(-inf) => NaN
cos(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.cos(Float.pi / 2) // => 0.0 (with numerical imprecision)
public let tan : (x : Float) -> Float
Returns the tangent of the radian angle x
.
Special cases:
tan(+inf) => NaN
tan(-inf) => NaN
tan(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.tan(Float.pi / 4) // => 1.0 (with numerical imprecision)
public let arcsin : (x : Float) -> Float
Returns the arc sine of x
in radians.
Special cases:
arcsin(x) => NaN if x > 1.0
arcsin(x) => NaN if x < -1.0
arcsin(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.arcsin(1.0) // => Float.pi / 2
public let arccos : (x : Float) -> Float
Returns the arc cosine of x
in radians.
Special cases:
arccos(x) => NaN if x > 1.0
arccos(x) => NaN if x < -1.0
arcos(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.arccos(1.0) // => 0.0
public let arctan : (x : Float) -> Float
Returns the arc tangent of x
in radians.
Special cases:
arctan(+inf) => pi / 2
arctan(-inf) => -pi / 2
arctan(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.arctan(1.0) // => Float.pi / 4
public let arctan2 : (y : Float, x : Float) -> Float
Given (y,x)
, returns the arc tangent in radians of y/x
based on the signs of both values to determine the correct quadrant.
Special cases:
arctan2(0.0, 0.0) => 0.0
arctan2(-0.0, 0.0) => -0.0
arctan2(0.0, -0.0) => pi
arctan2(-0.0, -0.0) => -pi
arctan2(+inf, +inf) => pi / 4
arctan2(+inf, -inf) => 3 * pi / 4
arctan2(-inf, +inf) => -pi / 4
arctan2(-inf, -inf) => -3 * pi / 4
arctan2(NaN, x) => NaN for any Float x
arctan2(y, NaN) => NaN for any Float y
Example:
import Float "mo:base/Float";
let sqrt2over2 = Float.sqrt(2) / 2;
Float.arctan2(sqrt2over2, sqrt2over2) // => Float.pi / 4
public let exp : (x : Float) -> Float
Returns the value of e
raised to the x
-th power.
Special cases:
exp(+inf) => +inf
exp(-inf) => 0.0
exp(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.exp(1.0) // => Float.e
public let log : (x : Float) -> Float
Returns the natural logarithm (base-e
) of x
.
Special cases:
log(0.0) => -inf
log(-0.0) => -inf
log(x) => NaN if x < 0.0
log(+inf) => +inf
log(NaN) => NaN
Example:
import Float "mo:base/Float";
Float.log(Float.e) // => 1.0
public func format(fmt : {#fix : Nat8; #exp : Nat8; #gen : Nat8; #hex : Nat8; #exact}, x : Float) : Text
Formatting. format(fmt, x)
formats x
to Text
according to the
formatting directive fmt
, which can take one of the following forms:
#fix prec
as fixed-point format with prec
digits#exp prec
as exponential format with prec
digits#gen prec
as generic format with prec
digits#hex prec
as hexadecimal format with prec
digits#exact
as exact format that can be decoded without loss.-0.0
is formatted with negative sign bit.
Positive infinity is formatted as inf
.
Negative infinity is formatted as -inf
.
NaN
is formatted as NaN
or -NaN
depending on its sign bit.
Example:
import Float "mo:base/Float";
Float.format(#exp 3, 123.0) // => "1.230e+02"
public let toText : Float -> Text
Conversion to Text. Use format(fmt, x)
for more detailed control.
-0.0
is formatted with negative sign bit.
Positive infinity is formatted as inf
.
Negative infinity is formatted as -inf
.
NaN
is formatted as NaN
or -NaN
depending on its sign bit.
Example:
import Float "mo:base/Float";
Float.toText(0.12) // => "0.12"
public let toInt64 : Float -> Int64
Conversion to Int64 by truncating Float, equivalent to toInt64(trunc(f))
Traps if the floating point number is larger or smaller than the representable Int64.
Also traps for inf
, -inf
, and NaN
.
Example:
import Float "mo:base/Float";
Float.toInt64(-12.3) // => -12
public let fromInt64 : Int64 -> Float
Conversion from Int64.
Note: The floating point number may be imprecise for large or small Int64.
Example:
import Float "mo:base/Float";
Float.fromInt64(-42) // => -42.0
public let toInt : Float -> Int
Conversion to Int.
Traps for inf
, -inf
, and NaN
.
Example:
import Float "mo:base/Float";
Float.toInt(1.2e6) // => +1_200_000
public let fromInt : Int -> Float
Conversion from Int. May result in Inf
.
Note: The floating point number may be imprecise for large or small Int values.
Returns inf
if the integer is greater than the maximum floating point number.
Returns -inf
if the integer is less than the minimum floating point number.
Example:
import Float "mo:base/Float";
Float.fromInt(-123) // => -123.0
public func equal(x : Float, y : Float) : Bool
Returns x == y
.
@deprecated Use Float.equalWithin()
as this function does not consider numerical errors.
public func notEqual(x : Float, y : Float) : Bool
Returns x != y
.
@deprecated Use Float.notEqualWithin()
as this function does not consider numerical errors.
public func equalWithin(
x : Float,
y : Float,
epsilon : Float
) : Bool
Determines whether x
is equal to y
within the defined tolerance of epsilon
.
The epsilon
considers numerical erros, see comment above.
Equivalent to Float.abs(x - y) <= epsilon
for a non-negative epsilon.
Traps if epsilon
is negative or NaN
.
Special cases:
equalWithin(+0.0, -0.0, epsilon) => true for any `epsilon >= 0.0`
equalWithin(-0.0, +0.0, epsilon) => true for any `epsilon >= 0.0`
equalWithin(+inf, +inf, epsilon) => true for any `epsilon >= 0.0`
equalWithin(-inf, -inf, epsilon) => true for any `epsilon >= 0.0`
equalWithin(x, NaN, epsilon) => false for any x and `epsilon >= 0.0`
equalWithin(NaN, y, epsilon) => false for any y and `epsilon >= 0.0`
Example:
import Float "mo:base/Float";
let epsilon = 1e-6;
Float.equalWithin(-12.3, -1.23e1, epsilon) // => true
public func notEqualWithin(
x : Float,
y : Float,
epsilon : Float
) : Bool
Determines whether x
is not equal to y
within the defined tolerance of epsilon
.
The epsilon
considers numerical erros, see comment above.
Equivalent to not equal(x, y, epsilon)
.
Traps if epsilon
is negative or NaN
.
Special cases:
notEqualWithin(+0.0, -0.0, epsilon) => false for any `epsilon >= 0.0`
notEqualWithin(-0.0, +0.0, epsilon) => false for any `epsilon >= 0.0`
notEqualWithin(+inf, +inf, epsilon) => false for any `epsilon >= 0.0`
notEqualWithin(-inf, -inf, epsilon) => false for any `epsilon >= 0.0`
notEqualWithin(x, NaN, epsilon) => true for any x and `epsilon >= 0.0`
notEqualWithin(NaN, y, epsilon) => true for any y and `epsilon >= 0.0`
Example:
import Float "mo:base/Float";
let epsilon = 1e-6;
Float.notEqualWithin(-12.3, -1.23e1, epsilon) // => false
public func less(x : Float, y : Float) : Bool
Returns x < y
.
Special cases:
less(+0.0, -0.0) => false
less(-0.0, +0.0) => false
less(NaN, y) => false for any Float y
less(x, NaN) => false for any Float x
Example:
import Float "mo:base/Float";
Float.less(Float.e, Float.pi) // => true
public func lessOrEqual(x : Float, y : Float) : Bool
Returns x <= y
.
Special cases:
lessOrEqual(+0.0, -0.0) => true
lessOrEqual(-0.0, +0.0) => true
lessOrEqual(NaN, y) => false for any Float y
lessOrEqual(x, NaN) => false for any Float x
Example:
import Float "mo:base/Float";
Float.lessOrEqual(0.123, 0.1234) // => true
public func greater(x : Float, y : Float) : Bool
Returns x > y
.
Special cases:
greater(+0.0, -0.0) => false
greater(-0.0, +0.0) => false
greater(NaN, y) => false for any Float y
greater(x, NaN) => false for any Float x
Example:
import Float "mo:base/Float";
Float.greater(Float.pi, Float.e) // => true
public func greaterOrEqual(x : Float, y : Float) : Bool
Returns x >= y
.
Special cases:
greaterOrEqual(+0.0, -0.0) => true
greaterOrEqual(-0.0, +0.0) => true
greaterOrEqual(NaN, y) => false for any Float y
greaterOrEqual(x, NaN) => false for any Float x
Example:
import Float "mo:base/Float";
Float.greaterOrEqual(0.1234, 0.123) // => true
public func compare(x : Float, y : Float) : {#less; #equal; #greater}
Defines a total order of x
and y
for use in sorting.
Note: Using this operation to determine equality or inequality is discouraged for two reasons:
equalWithin(x, y, espilon)
or
notEqualWithin(x, y, epsilon)
to test for equality or inequality, respectively.NaN
are here considered equal if their sign matches, which is different to the standard equality
by ==
or when using equal()
or notEqual()
.Total order:
-0.0
)+0.0
)Example:
import Float "mo:base/Float";
Float.compare(0.123, 0.1234) // => #less
public func neg(x : Float) : Float
Returns the negation of x
, -x
.
Changes the sign bit for infinity.
Special cases:
neg(+inf) => -inf
neg(-inf) => +inf
neg(+NaN) => -NaN
neg(-NaN) => +NaN
neg(+0.0) => -0.0
neg(-0.0) => +0.0
Example:
import Float "mo:base/Float";
Float.neg(1.23) // => -1.23
public func add(x : Float, y : Float) : Float
Returns the sum of x
and y
, x + y
.
Note: Numerical errors may occur, see comment above.
Special cases:
add(+inf, y) => +inf if y is any Float except -inf and NaN
add(-inf, y) => -inf if y is any Float except +inf and NaN
add(+inf, -inf) => NaN
add(NaN, y) => NaN for any Float y
The same cases apply commutatively, i.e. for add(y, x)
.
Example:
import Float "mo:base/Float";
Float.add(1.23, 0.123) // => 1.353
public func sub(x : Float, y : Float) : Float
Returns the difference of x
and y
, x - y
.
Note: Numerical errors may occur, see comment above.
Special cases:
sub(+inf, y) => +inf if y is any Float except +inf or NaN
sub(-inf, y) => -inf if y is any Float except -inf and NaN
sub(x, +inf) => -inf if x is any Float except +inf and NaN
sub(x, -inf) => +inf if x is any Float except -inf and NaN
sub(+inf, +inf) => NaN
sub(-inf, -inf) => NaN
sub(NaN, y) => NaN for any Float y
sub(x, NaN) => NaN for any Float x
Example:
import Float "mo:base/Float";
Float.sub(1.23, 0.123) // => 1.107
public func mul(x : Float, y : Float) : Float
Returns the product of x
and y
, x * y
.
Note: Numerical errors may occur, see comment above.
Special cases:
mul(+inf, y) => +inf if y > 0.0
mul(-inf, y) => -inf if y > 0.0
mul(+inf, y) => -inf if y < 0.0
mul(-inf, y) => +inf if y < 0.0
mul(+inf, 0.0) => NaN
mul(-inf, 0.0) => NaN
mul(NaN, y) => NaN for any Float y
The same cases apply commutatively, i.e. for mul(y, x)
.
Example:
import Float "mo:base/Float";
Float.mul(1.23, 1e2) // => 123.0
public func div(x : Float, y : Float) : Float
Returns the division of x
by y
, x / y
.
Note: Numerical errors may occur, see comment above.
Special cases:
div(0.0, 0.0) => NaN
div(x, 0.0) => +inf for x > 0.0
div(x, 0.0) => -inf for x < 0.0
div(x, +inf) => 0.0 for any x except +inf, -inf, and NaN
div(x, -inf) => 0.0 for any x except +inf, -inf, and NaN
div(+inf, y) => +inf if y >= 0.0
div(+inf, y) => -inf if y < 0.0
div(-inf, y) => -inf if y >= 0.0
div(-inf, y) => +inf if y < 0.0
div(NaN, y) => NaN for any Float y
div(x, NaN) => NaN for any Float x
Example:
import Float "mo:base/Float";
Float.div(1.23, 1e2) // => 0.0123
public func rem(x : Float, y : Float) : Float
Returns the floating point division remainder x % y
,
which is defined as x - trunc(x / y) * y
.
Note: Numerical errors may occur, see comment above.
Special cases:
rem(0.0, 0.0) => NaN
rem(x, y) => +inf if sign(x) == sign(y) for any x and y not being +inf, -inf, or NaN
rem(x, y) => -inf if sign(x) != sign(y) for any x and y not being +inf, -inf, or NaN
rem(x, +inf) => x for any x except +inf, -inf, and NaN
rem(x, -inf) => x for any x except +inf, -inf, and NaN
rem(+inf, y) => NaN for any Float y
rem(-inf, y) => NaN for any Float y
rem(NaN, y) => NaN for any Float y
rem(x, NaN) => NaN for any Float x
Example:
import Float "mo:base/Float";
Float.rem(7.2, 2.3) // => 0.3 (with numerical imprecision)
public func pow(x : Float, y : Float) : Float
Returns x
to the power of y
, x ** y
.
Note: Numerical errors may occur, see comment above.
Special cases:
pow(+inf, y) => +inf for any y > 0.0 including +inf
pow(+inf, 0.0) => 1.0
pow(+inf, y) => 0.0 for any y < 0.0 including -inf
pow(x, +inf) => +inf if x > 0.0 or x < 0.0
pow(0.0, +inf) => 0.0
pow(x, -inf) => 0.0 if x > 0.0 or x < 0.0
pow(0.0, -inf) => +inf
pow(x, y) => NaN if x < 0.0 and y is a non-integral Float
pow(-inf, y) => +inf if y > 0.0 and y is a non-integral or an even integral Float
pow(-inf, y) => -inf if y > 0.0 and y is an odd integral Float
pow(-inf, 0.0) => 1.0
pow(-inf, y) => 0.0 if y < 0.0
pow(-inf, +inf) => +inf
pow(-inf, -inf) => 1.0
pow(NaN, y) => NaN if y != 0.0
pow(NaN, 0.0) => 1.0
pow(x, NaN) => NaN for any Float x
Example:
import Float "mo:base/Float";
Float.pow(2.5, 2.0) // => 6.25