这段代码包含了一个万能函数modf
,使用它可以定义出truncatef
和roundf
函数:
# let truncatef x = snd (modf x);;
val truncatef : float -> float = <fun>
# truncatef 3.14;;
- : float = 3.
< p >
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.
然而,使用
floor
可以更简洁(高效)地表达。
但是,两种舍入函数都有一些小问题,正如在core
实现中所述的注释:
let round_nearest_lb = -.(2. ** 52.)
let round_nearest_ub = 2. ** 52.
因此,实现四舍五入的更正确的方法是(来自核心库):
let round_nearest t =
if t >= round_nearest_lb && t <= round_nearest_ub then
floor (t +. 0.5)
else
t
但即使是round_nearest
也不是完美的,例如:
# round_nearest 0.49999999999999994;;
- : float = 1.
这个 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
- : float = 0.
- : float = 0.
- : float = -1.
- : float = 1.
- : float = -1.
这只是其中一种四舍五入的策略,即最近的整数(直观的方法)。还有其他的策略,它们也有自己的注意事项。