Does OCaml have C functions (like round () and trunc ()?

The OCaml standard library includes several floating point functions equivalent to C, for example mod_float for C fmod() , an exponent operator ** for C pow() and other functions such as ceil , log , etc.

But does it also include equivalents for round() and trunc() ? There is truncate / int_of_float , but their type is float -> int , not float -> float .

+6
source share
4 answers

It contains the modf function, which is a Swiss knife function with which you can define the truncatef and roundf :

 # let truncatef x = snd (modf x);; val truncatef : float -> float = <fun> # truncatef 3.14;; - : float = 3. 

The round function can also be expressed using modf

 # let roundf x = snd (modf (x +. copysign 0.5 x));; val roundf : float -> float = <fun> # roundf 3.14;; - : float = 3. # roundf 3.54;; - : float = 4. # roundf (~-.3.54);; - : float = -4. 

However, it can be expressed more concisely (and effectively) using floor

 # let roundf x = floor (x +. 0.5) 

But both rounding functions are a bit erroneous as the comment in the core implementation:

 (* Outside of the range [round_nearest_lb..round_nearest_ub], all representable doubles are integers in the mathematical sense, and [round_nearest] should be identity. However, for odd numbers with the absolute value between 2**52 and 2**53, the formula [round_nearest x = floor (x + 0.5)] does not hold: # let naive_round_nearest x = floor (x +. 0.5);; # let x = 2. ** 52. +. 1.;; val x : float = 4503599627370497. # naive_round_nearest x;; - : float = 4503599627370498. *) let round_nearest_lb = -.(2. ** 52.) let round_nearest_ub = 2. ** 52. 

So, a more correct way to implement rounding would be (from the Core library):

 let round_nearest t = if t >= round_nearest_lb && t <= round_nearest_ub then floor (t +. 0.5) else t 

But even this round_nearest not perfect, for example:

 # round_nearest 0.49999999999999994;; - : float = 1. 

This 0.49999999999999994 is the immediate predecessor of 0.5 . The Pascal blog contains suggestions for solving this problem. The following should work in OCaml:

 let round_nearest t = if t >= round_nearest_lb && t <= round_nearest_ub then floor (t +. 0.49999999999999994) else t # round_nearest 0.49999999999999994;; - : float = 0. # round_nearest (~-.0.49999999999999994);; - : float = 0. # round_nearest (~-.1.49999999999999994);; - : float = -1. # round_nearest 0.5;; - : float = 1. # round_nearest ~-.0.5;; - : float = -1. # 

And this is only one rounding policy, rounded to the nearest (intuitive). There are other policies that have their own reservations.

+7
source

The Core library has a Float module with many such features.

+4
source

To truncate, someone has already given you the answer:

 let truncatef x = snd (modf x); 

For the round, I suggest: BatFloat.round_to_int or BatFloat.round

More on this .

+1
source

If you want the truncate function to be of type float -> float , you can do this, but it is very ugly:

 let mytruncate x = float_of_int (truncate x) 
0
source

Source: https://habr.com/ru/post/988785/


All Articles