package floatml

  1. Overview
  2. Docs
Floats (f16, f32, f64, f128) for OCaml

Install

dune-project
 Dependency

Authors

Maintainers

Sources

v0.2.1.tar.gz
md5=e42bdd511121f3bd65f9fbcdb71be4a8
sha512=118ef63d0a101465a788b00501d708eacfff402fdce5ca0f57f62d80ee5e585e221cc270760c7702b705a9c10e89f2bbe1b59327dcf67bf4ea25f4d8dd216fd3

Description

Deterministic, IEEE-754-compliant interface for floating point operators over f16, f32, f64 and f128, backed by Rust's rustc_apfloat. Requires a Rust toolchain (cargo, 1.77 or newer) to build.

Added to opam-repository:

README

floatml - IEEE-754 floats for OCaml

Add Float16, Float32, Float64, and Float128 types to OCaml, with full support for arithmetic, comparisons, and conversions to bit representation.

It also provides AnyFloat, which hides the specific float type but will error if mismatched sizes are used together.

This project aims at being an easy to use, correct, and efficient implementation of IEEE-754 floating point arithmetic for OCaml.

Implementation

All four formats are evaluated in software by Rust's rustc_apfloat, the LLVM APFloat port that rustc itself uses for compile-time float constant evaluation. This makes every result correctly rounded and bit-for-bit deterministic across every platform, and leans on a battle-tested soft-float rather than a hand-written one.

The numeric core lives in rust/lib.rs (macros generate the bindings for all four precisions); src/floatml.ml is a thin OCaml binding layer over it. Building therefore requires a Rust toolchain (cargo) on PATH in addition to the OCaml dependencies.

Performance and allocation

Crossing into Rust is the dominant cost of an operation, so the binding is built to make that crossing as close to free as possible. In native code an operation on Float16, Float32 or Float64 is a direct C call that touches neither the OCaml runtime nor the OCaml heap, and allocates at most the box for its result:

operation

ns/op

words allocated

F64.lt, F64.is_nan, F64.compare

2–6

0

F16.add (and every other F16 operator)

15

0

F32.add / F64.add

16

3 (the Int32.t/Int64.t result)

F128.add

20

4 (one custom block)

AnyFloat.add

17

5

Comparisons, the classification predicates, compare and bits_equal allocate nothing at any precision. Float16 operators allocate nothing either, its bit pattern being an immediate int. Float128 carries its 128 bits whole, in a custom block. Only of_string and the integer conversions, which have to return an option of a bit pattern, allocate more than their result.

Coverage

Every operation IEEE 754 requires of a binary format is here.

Arithmetic rounds to nearest-ties-to-even; an explicit rounding direction is taken where IEEE 754 makes it a parameter (roundToIntegral, convertToInteger, convertFromInt, and convertFormat).

Note we do not implement transcendentals, because they are non-deterministic across platforms.

Dependencies (4)

  1. conf-rust-2024 build
  2. zarith >= "1.13"
  3. dune >= "3.0"
  4. ocaml >= "4.14.0"

Dev Dependencies (1)

  1. odoc with-doc

Used by

None

Conflicts

None