Float

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:

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:

type Float = Prim.Types.Float

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:

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:

-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:

Total order:

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