I'm surprised the performance of the two implementations is so close. Aren't floating-point numbers in OCaml usually boxed? Is the compiler smart enough to optimize away the boxes in this situation?
The floats in the structs are unboxed. Float arrays and all-float structs have a special representation[1] in the compiler so they are stored unboxed. I believe the developers of OCaml have expressed some regrets about this, but in this particular case it's likely to be a win.
Within functions, the OCaml compiler can assign floats to registers, so those would also be unboxed at least for the duration of the function.
Within functions, the OCaml compiler can assign floats to registers, so those would also be unboxed at least for the duration of the function.
[1] https://realworldocaml.org/v1/en/html/memory-representation-...