OCaml的标准库包含几个等同于C的浮点函数,例如C mod_float
的{{1}},C fmod()
的取幂运算符**
等。 pow()
,ceil
等功能
但是它还包括log
和round()
的等价物吗?有trunc()
/ truncate
,但其类型为int_of_float
而不是float -> int
。
答案 0 :(得分:7)
它包含modf
函数,这是一个瑞士刀函数,您可以使用它来定义truncatef
和roundf
函数:
# let truncatef x = snd (modf x);;
val truncatef : float -> float = <fun>
# truncatef 3.14;;
- : float = 3.
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
# let roundf x = floor (x +. 0.5)
但正如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.
因此,实现舍入的更正确的方法是(来自Core库):
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的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.
#
这只是一个舍入政策,舍入到最近(直观的)。还有其他政策,有自己的警告。
答案 1 :(得分:4)
Core
库有一个Float模块,其中包含许多此类函数。
答案 2 :(得分:1)
对于截断,有人已经给你一个答案:
let truncatef x = snd (modf x);
对于回合,我建议:
BatFloat.round_to_int
或BatFloat.round
查看this了解详情。
答案 3 :(得分:0)
如果你想要一个类型为float -> float
的函数截断,你可以这样做,但它非常难看:
let mytruncate x = float_of_int (truncate x)