Hi :) Wanted to announce a new package I worked on over the past week I just published, floatml! It’s a tiny wrapper around Rust’s soft float library (rustc_apfloat), enabling fast and efficient IEEE-754 float16, float32, float64 and float128 in OCaml. I also made sure the code allocates as little as possible, so it should be reasonably efficient.
Disclaimer: a good chunk of the code is LLM-authored. I chose the interface I wanted and guided it, but the glue code with Rust is LLM generated (and extensively tested!)
I had to create it for Soteria, where we need reductions for concrete float operations, to avoid using Z3 when possible. Maybe you’ll find a use for it too!
Because Float128’s bit pattern is an (int64 * int64) pair, every result costs a tuple and two boxed words.
Here’s a (possibly very bad) idea: use a record with two float fields (or just a 2-element floatarray) to make use of the flat float array/record optimization, but just store the int64 bits in them, i.e., really just all the bits of a float128 contiguously. (Like poor man’s OxCaml unboxing.)
If you never look at their contents as float on the OCaml side, it might be fine??
EDIT: Or at that point it would probably be better to use a custom block like a boxed int64 is as well.
Oh that’s clever! The issue with using a record of floats or an array is that for polymorphic comparisons we inherit float’s comparison, which would break some stuff (since all NaNs are equal, and +0 == -0). Ended up going with a custom block, which drops allocations of F128.add from 9 to 4 :D