OCaml是否具有类似C的round()和trunc()函数?

ano*_*nol 6 floating-point ocaml

OCaml的标准库包括多个浮点功能等效至C的,如mod_float对于C的fmod(),幂运算符**对于C的pow(),和其他功能,如ceil,log

但它是否还包括等价物round()trunc()?有truncate/ int_of_float,但他们的类型是float -> int和不float -> float.

ivg*_*ivg 7

它包含modf函数,即瑞士刀函数,您可以使用它来定义truncatefroundf函数:

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

round功能也可以表示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.
Run Code Online (Sandbox Code Playgroud)

然而,它可以更简洁(和有效)地表达 floor

# let roundf x = floor (x +. 0.5)
Run Code Online (Sandbox Code Playgroud)

但是两个舍入函数都有点错误,正如在core实现中的评论所述:

(* 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.
Run Code Online (Sandbox Code Playgroud)

因此,实现舍入的一些更正确的方法是(来自Core库):

let round_nearest t =
  if t >= round_nearest_lb && t <= round_nearest_ub then
    floor (t +. 0.5)
  else
    t
Run Code Online (Sandbox Code Playgroud)

但即便如此round_nearest,也不是完美的,例如:

# round_nearest 0.49999999999999994;;
- : float = 1.
Run Code Online (Sandbox Code Playgroud)

0.49999999999999994是它的前身0.5.Pascal的博客包含有关如何解决此问题的建议.以下内容适用于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.
# 
Run Code Online (Sandbox Code Playgroud)

这只是一个舍入政策,舍入到最近(直观的).还有其他政策,有自己的警告.