OCaml的标准库包括几个等同于C语言的浮点函数,例如C的fmod()的mod_float,C的pow()的取幂运算符**,以及ceil,log等其他函数.
但是它还包括round()和trunc()的等价物吗?有truncate / int_of_float,但它们的类型是float – > int而不是float – >浮动.
解决方法
它包含modf函数,即瑞士刀函数,您可以使用它来定义truncatef和roundf函数:
# let truncatef x = snd (modf x);; val truncatef : float -> float = <fun> # truncatef 3.14;; - : float = 3.
圆函数也可以用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.
然而,它可以用地板更简洁(和有效)地表达
# let roundf x = floor (x +. 0.5)
(* 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.
因此,实现舍入的一些更正确的方法是(来自Core库):
let round_nearest t = if t >= round_nearest_lb && t <= round_nearest_ub then floor (t +. 0.5) else t
但即使是这个最圆的也不是完美的,例如:
# round_nearest 0.49999999999999994;; - : float = 1.
这个0.49999999999999994是0.5的前身. Pascal的blog包含有关如何解决此问题的建议.以下内容适用于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. #
这只是一个舍入政策,舍入到最近(直观的).还有其他政策,有自己的警告.