package reason-standard

  1. Overview
  2. Docs

A module for working with floating-point numbers.

Valid syntax for floats includes:

42.
42.0
(-7.)
3.14
(-0.1234)
123_456.123_456
6.022e23   (* = (6.022 * 10^23) *)
6.022e+23  (* = (6.022 * 10^23) *)
1.602e-19  (* = (1.602 * 10^-19) *)
1e3        (* = (1 * 10 ** 3) = 1000. *)

Without opening this module you can use the . suffixed operators e.g

1. +. 2. /. 0.25 *. 2. = 17. 

But by opening this module locally you can use the un-suffixed operators

Float.((10.0 - 1.5 / 0.5) ** 3.0) = 2401.0

Historical Note: The particular details of floats (e.g. NaN) are specified by IEEE 754 which is literally hard-coded into almost all CPUs in the world.

Functions for working with floating point numbers.

type t = float

Constants

val zero : float

The literal 0.0 as a named value

val one : float

The literal 1.0 as a named value

val nan : float

NaN as a named value. NaN stands for not a number.

Note comparing values with Float.nan will always return false even if the value you are comparing against is also NaN.

e.g

let isNotANumber x = Float.(x = nan) in

isNotANumber nan = false

For detecting Nan you should use Float.isNaN

val infinity : float

Positive infinity

Float.log ~base:10.0 0.0 = Float.infinity
val negativeInfinity : float

Negative infinity, see Float.infinity

val e : float

An approximation of Euler's number.

val pi : float

An approximation of pi.

val epsilon : float

The smallest interval between two representable numbers.

val largestValue : float

The largest (furthest from zero) representable positive float

val smallestValue : float

The smallest representable positive float. The closest to zero without actually being zero.

val maximumSafeInteger : float

For floats greater than maximumSafeInteger, it no longer holds that Float.(n + 1.) > n

val minimumSafeInteger : float

For floats less than minimumSafeInteger, it no longer holds that Float.(n - 1.) < n

Create

val ofInt : int -> float

Convert an Int to a float

Examples

Float.ofInt 5 = 5.0
Float.ofInt 0 = 0.0
Float.ofInt -7 = -7.0
val ofString : string -> float option

Convert a String to a float.

Parses nan and infinity case-insensitive.

Examples

Float.ofString "4.667" = Some 4.667
Float.ofString "-4.667" = Some (-4.667)
Float.ofString "Hamster" = None
Float.ofString "NaN" = Some Float.nan
Float.ofString "nan" = Some Float.nan
Float.ofString "Infinity" = Some Float.infinity

Basic arithmetic and operators

val add : float -> float -> float

Addition for floating point numbers.

Although ints and floats support many of the same basic operations such as addition and subtraction you cannot add an int and a float directly which means you need to use functions like Int.toFloat to convert both values to the same type.

So if you needed to add a List.length to a float for some reason, you could:

Float.add 3.14 (Int.toFloat (List.length [1,2,3])) = 6.14

or

Float.roundToInt 3.14 + List.length [1,2,3] = 6

Languages like Java and JavaScript automatically convert int values to float values when you mix and match. This can make it difficult to be sure exactly what type of number you are dealing with and cause unexpected behavior.

OCaml has opted for a design that makes all conversions explicit.

Examples

Float.add 3.14 3.14 = 6.28
Float.(3.14 + 3.14 = 6.28)
val (+) : float -> float -> float
val subtract : float -> float -> float

Subtract numbers

Alternatively the - operator can be used

Examples

Float.subtract 4.0 3.0 = 1.0
Float.(4.0 - 3.0) = 1.0
val (-) : float -> float -> float
val multiply : float -> float -> float

Multiply numbers

Alternatively the * operator can be used

Examples

Float.multiply 2.0 7.0 = 14.0
Float.(2.0 * 7.0) = 14.0
val (*) : float -> float -> float
val divide : float -> by:float -> float

Floating-point division:

Alternatively the / operator can be used

Examples

Float.divide 3.14 ~by:2.0 = 1.57
Float.(3.14 / 2.0) = 1.57
val (/) : float -> float -> float
val power : base:float -> exponent:float -> float

Exponentiation, takes the base first, then the exponent.

Alternatively the ** operator can be used

Examples

Float.power ~base:7.0 ~exponent:3.0 = 343.0
Float.(7.0 ** 3.0) = 343.0
val (**) : float -> float -> float
val negate : float -> float

Flips the 'sign' of a float so that positive floats become negative and negative integers become positive.

Zero stays as it is.

Alternatively an operator is available

Examples

Float.(~- 4.0) = (-4.0)
Float.negate 8 = (-8)
Float.negate (-7) = 7
Float.negate 0 = 0
val (~-) : float -> float
val absolute : float -> float

Get the absolute value of a number.

Examples

Float.absolute 8. = 8.
Float.absolute (-7) = 7
Float.absolute 0. = 0.
val maximum : float -> float -> float

Returns the larger of two floats, if both arguments are equal, returns the first argument

If either (or both) of the arguments are NaN, returns NaN

Examples

Float.maximum 7. 9. = 9.
Float.maximum (-4.) (-1.) = (-1.)
Float.(isNaN (maximum 7. nan)) = true
val minimum : float -> float -> float

Returns the smaller of two floats, if both arguments are equal, returns the first argument

If either (or both) of the arguments are NaN, returns NaN

Examples

Float.minimum 7.0 9.0 = 7.0
Float.minimum (-4.0) (-1.0) = (-4.0)
Float.(isNaN (minimum 7. nan)) = true
val clamp : float -> lower:float -> upper:float -> float

Clamps n within the inclusive lower and upper bounds.

Exceptions

Throws an Invalid_argument exception if lower > upper

Examples

Float.clamp ~lower:0. ~upper:8. 5. = 5.
Float.clamp ~lower:0. ~upper:8. 9. = 8.
Float.clamp ~lower:(-10.) ~upper:(-5.) 5. = -5.

Fancier math

val squareRoot : float -> float

Take the square root of a number.

squareRoot returns NaN when its argument is negative. See Float.nan for more.

Examples

Float.squareRoot 4.0 = 2.0
Float.squareRoot 9.0 = 3.0
val log : float -> base:float -> float

Calculate the logarithm of a number with a given base.

Examples

Float.log ~base:10. 100. = 2.
Float.log ~base:2. 256. = 8.

Query

val isNaN : float -> bool

Determine whether a float is an undefined or unrepresentable number.

Note this function is more useful than it might seem since NaN does not equal Nan:

Float.(nan = nan) = false

Examples

Float.isNaN (0.0 / 0.0) = true
Float.(isNaN (squareRoot (-1.0))) = true
Float.isNaN (1.0 / 0.0) = false  (* Float.infinity {b is} a number *)
Float.isNaN 1. = false
val isFinite : float -> bool

Determine whether a float is finite number. True for any float except Infinity, -Infinity or NaN

Notice that NaN is not finite!

Examples

Float.isFinite (0. / 0.) = false
Float.(isFinite (squareRoot (-1.))) = false
Float.isFinite (1. / 0.) = false
Float.isFinite 1. = true
Float.(isFinite nan) = false
val isInfinite : float -> bool

Determine whether a float is positive or negative infinity.

Examples

Float.isInfinite (0. / 0.) = false
Float.(isInfinite (squareRoot (-1.))) = false
Float.isInfinite (1. / 0.) = true
Float.isInfinite 1. = false
Float.(isInfinite nan) = false
val isInteger : float -> bool

Determine whether the passed value is an integer.

Examples

Float.isInteger 4.0 = true
Float.isInteger Float.pi = false
val isSafeInteger : float -> bool

Determine whether the passed value is a safe integer.

Safe integers have the property that x +. 1. > x.

This is true for numbers between -(2**53 - 1) and 2**53 - 1.

Examples

Float.isSafeInteger 4.0 = true
Float.isSafeInteger Float.pi = false
Float.(isSafeInteger (maximumSafeInteger + 1.)) = false
val inRange : float -> lower:float -> upper:float -> bool

Checks if a float is between lower and up to, but not including, upper.

If lower is not specified, it's set to to 0.0.

Exceptions

Throws an Invalid_argument exception if lower > upper

Examples

Float.inRange ~lower:2. ~upper:4. 3. = true
Float.inRange ~lower:1. ~upper:2. 2. = false
Float.inRange ~lower:5.2 ~upper:7.9 9.6 = false

Angles

type radians = float

This type is just an alias for float.

Its purpose is to make understanding the signatures of the following functions a little easier.

val hypotenuse : float -> float -> float

hypotenuse x y returns the length of the hypotenuse of a right-angled triangle with sides of length x and y, or, equivalently, the distance of the point (x, y) to (0, 0).

Examples

Float.hypotenuse 3. 4. = 5.
val degrees : float -> radians

Converts an angle in degrees to Float.radians.

Examples

Float.degrees 180. = Float.pi
Float.degrees 360. = Float.pi * 2.
Float.degrees 90. = Float.pi /. 2.
val radians : float -> radians

Convert a Float.t to radians.

Note This function doesn't actually do anything to its argument, but can be useful to indicate intent when inter-mixing angles of different units within the same function.

Examples

Float.(radians pi) = 3.141592653589793
val turns : float -> radians

Convert an angle in turns into Float.radians.

One turn is equal to 360 degrees.

Examples

Float.(turns (1. / 2.)) = pi
Float.(turns 1. = degrees 360.)

Polar coordinates

val ofPolar : (float * radians) -> float * float

Convert polar coordinates (radius, radians) to Cartesian coordinates (x,y).

Examples

Float.(ofPolar (squareRoot 2., degrees 45.)) = (1., 1.)
val toPolar : (float * float) -> float * radians

Convert Cartesian coordinates (x, y) to polar coordinates (radius, radians).

Examples

Float.toPolar (-1.0, 0.0) = (1.0, Float.pi)
Float.toPolar (3.0, 4.0) = (5.0, 0.9272952180016122)
Float.toPolar (5.0, 12.0) = (13.0, 1.1760052070951352)
val cos : radians -> float

Figure out the cosine given an angle in radians.

Examples

Float.(cos (degrees 60.)) = 0.5000000000000001
Float.(cos (radians (pi / 3.))) = 0.5000000000000001
val acos : float -> radians

Figure out the arccosine for adjacent / hypotenuse in radians:

Examples

Float.(acos (radians 1.0 / 2.0)) = Float.radians 1.0471975511965979 (* 60 degrees or pi/3 radians *)
val sin : radians -> float

Figure out the sine given an angle in radians.

Examples

Float.(sin (degrees 30.)) = 0.49999999999999994
Float.(sin (radians (pi / 6.))) = 0.49999999999999994
val asin : float -> radians

Figure out the arcsine for opposite / hypotenuse in radians:

Examples

Float.(asin (1.0 / 2.0)) = 0.5235987755982989 (* 30 degrees or pi / 6 radians *)
val tan : radians -> float

Figure out the tangent given an angle in radians.

Examples

Float.(tan (degrees 45.)) = 0.9999999999999999
Float.(tan (radians (pi / 4.))) = 0.9999999999999999
Float.(tan (pi / 4.)) = 0.9999999999999999
val atan : float -> radians

This helps you find the angle (in radians) to an (x, y) coordinate, but in a way that is rarely useful in programming.

You probably want atan2 instead!

This version takes y / x as its argument, so there is no way to know whether the negative signs comes from the y or x value. So as we go counter-clockwise around the origin from point (1, 1) to (1, -1) to (-1,-1) to (-1,1) we do not get angles that go in the full circle:

Notice that everything is between pi / 2 and -pi/2. That is pretty useless for figuring out angles in any sort of visualization, so again, check out Float.atan2 instead!

Examples

Float.atan (1. /. 1.) = 0.7853981633974483  (* 45 degrees or pi/4 radians *)
Float.atan (1. /. -1.) = -0.7853981633974483  (* 315 degrees or 7 * pi / 4 radians *)
Float.atan (-1. /. -1.) = 0.7853981633974483 (* 45 degrees or pi/4 radians *)
Float.atan (-1. /.  1.) = -0.7853981633974483 (* 315 degrees or 7 * pi/4 radians *)
val atan2 : y:float -> x:float -> float

This helps you find the angle (in radians) to an (x, y) coordinate.

So rather than Float.(atan (y / x)) you can Float.atan2 ~y ~x and you can get a full range of angles:

Examples

Float.atan2 ~y:1. ~x:1. = 0.7853981633974483  (* 45 degrees or pi/4 radians *)
Float.atan2 ~y:1. ~x:(-1.) = 2.3561944901923449  (* 135 degrees or 3 * pi/4 radians *)
Float.atan2 ~y:(-1.) ~x:(-1.) = -(2.3561944901923449) (* 225 degrees or 5 * pi/4 radians *)
Float.atan2 ~y:(-1.) ~x:1. = -(0.7853981633974483) (* 315 degrees or 7 * pi/4 radians *)

Rounding

type direction = [
  1. | `Zero
  2. | `AwayFromZero
  3. | `Up
  4. | `Down
  5. | `Closest of [ `Zero | `AwayFromZero | `Up | `Down | `ToEven ]
]

The possible directions availible when doing Float.round.

See Float.round for what each variant represents.

val round : ?direction:direction -> float -> float

Round a number, by default to the to the closest int with halves rounded `Up (towards positive infinity)

Other rounding strategies are available by using the optional ~direction labelelled.

Examples

Float.round 1.2 = 1.0
Float.round 1.5 = 2.0
Float.round 1.8 = 2.0
Float.round -1.2 = -1.0
Float.round -1.5 = -1.0
Float.round -1.8 = -2.0

Towards zero

Float.round ~direction:`Zero 1.2 = 1.0
Float.round ~direction:`Zero 1.5 = 1.0
Float.round ~direction:`Zero 1.8 = 1.0
Float.round ~direction:`Zero (-1.2) = -1.0
Float.round ~direction:`Zero (-1.5) = -1.0
Float.round ~direction:`Zero (-1.8) = -1.0

Away from zero

Float.round ~direction:`AwayFromZero 1.2 = 1.0
Float.round ~direction:`AwayFromZero 1.5 = 1.0
Float.round ~direction:`AwayFromZero 1.8 = 1.0
Float.round ~direction:`AwayFromZero (-1.2) = -1.0
Float.round ~direction:`AwayFromZero (-1.5) = -1.0
Float.round ~direction:`AwayFromZero (-1.8) = -1.0

Towards infinity

This is also known as Float.ceiling

Float.round ~direction:`Up 1.2 = 1.0
Float.round ~direction:`Up 1.5 = 1.0
Float.round ~direction:`Up 1.8 = 1.0
Float.round ~direction:`Up (-1.2) = -1.0
Float.round ~direction:`Up (-1.5) = -1.0
Float.round ~direction:`Up (-1.8) = -1.0

Towards negative infinity

This is also known as Float.floor

List.map  ~f:(Float.round ~direction:`Down) [-1.8; -1.5; -1.2; 1.2; 1.5; 1.8] = [-2.0; -2.0; -2.0; 1.0 1.0 1.0]

To the closest integer

Rounding a number x to the closest integer requires some tie-breaking for when the fraction part of x is exactly 0.5.

Halves rounded towards zero

List.map  ~f:(Float.round ~direction:(`Closest `AwayFromZero)) [-1.8; -1.5; -1.2; 1.2; 1.5; 1.8] = [-2.0; -1.0; -1.0; 1.0 1.0 2.0]

Halves rounded away from zero

This method is often known as commercial rounding

List.map  ~f:(Float.round ~direction:(`Closest `AwayFromZero)) [-1.8; -1.5; -1.2; 1.2; 1.5; 1.8] = [-2.0; -2.0; -1.0; 1.0 2.0 2.0]

Halves rounded down

List.map  ~f:(Float.round ~direction:(`Closest `Down)) [-1.8; -1.5; -1.2; 1.2; 1.5; 1.8] = [-2.0; -2.0; -1.0; 1.0 1.0 2.0]

Halves rounded up

This is the default.

Float.round 1.5 is the same as Float.round ~direction:(`Closest `Up) 1.5

Halves rounded towards the closest even number

Float.round ~direction:(`Closest `ToEven) -1.5 = -2.0
Float.round ~direction:(`Closest `ToEven) -2.5 = -2.0
val floor : float -> float

Floor function, equivalent to Float.round ~direction:`Down.

Examples

Float.floor 1.2 = 1.0
Float.floor 1.5 = 1.0
Float.floor 1.8 = 1.0
Float.floor -1.2 = -2.0
Float.floor -1.5 = -2.0
Float.floor -1.8 = -2.0
val ceiling : float -> float

Ceiling function, equivalent to Float.round ~direction:`Up.

Examples

Float.ceiling 1.2 = 2.0
Float.ceiling 1.5 = 2.0
Float.ceiling 1.8 = 2.0
Float.ceiling -1.2 = (-1.0)
Float.ceiling -1.5 = (-1.0)
Float.ceiling -1.8 = (-1.0)
val truncate : float -> float

Ceiling function, equivalent to Float.round ~direction:`Zero.

Examples

Float.truncate 1.0 = 1.
Float.truncate 1.2 = 1.
Float.truncate 1.5 = 1.
Float.truncate 1.8 = 1.
Float.truncate (-1.2) = -1.
Float.truncate (-1.5) = -1.
Float.truncate (-1.8) = -1.

Convert

val toInt : float -> int option

Converts a float to an Int by ignoring the decimal portion. See Float.truncate for examples.

Returns None when trying to round a float which can't be represented as an int such as Float.nan or Float.infinity or numbers which are too large or small.

You probably want to use some form of Float.round prior to using this function.

Examples

Float.(toInt 1.6) = (Some 1)
Float.(toInt 2.0) = (Some 2)
Float.(toInt 5.683) = (Some 5)
Float.(toInt nan) = None
Float.(toInt infinity) = None
Float.(round 1.6 |> toInt) = Some 2
val toString : float -> string

Convert a float to a String

The behaviour of this function is platform specific

Compare

val equal : float -> float -> bool

Test two floats for equality

val compare : float -> float -> int

Compare two floats