我正在尝试做一些超级简单的事情...
let Average (a : float list) : (float option) =
let add (x : float) (y : float) = x+y
match a.Length with
| 0 -> None
| 1 -> None
| _ -> Some((List.fold add 0.0 a)/(float)a.Length)
let CompareResult func input expected =
(func input) = expected
这是我的两个功能。 当我做 CompareResult平均[5.8; 6.6; 9.4; 3.5; 4.0](约5.86) 我越来越假了。
任何可能实现此目标的想法都会受到赞赏。 谢谢
答案 0 :(得分:2)
除了内部表示法的局限性导致的差异外,该问题还可能是由于在浮点算术中计算平均值时精度下降所致。
5.86.ToString "G17"
// val it : string = "5,8600000000000003"
(Seq.average [5.8;6.6;9.4;3.5;4.0]).ToString "G17"
// val it : string = "5,8599999999999994"
考虑使用更合适的数字数据类型:
Seq.average [5.8;6.6;9.4;3.5;4.0] = 5.86
// false
Seq.average [5.8M;6.6M;9.4M;3.5M;4.0M] = 5.86M
// true
要回答实际问题,如何对Option<float>
值进行相等测试:通过“提起”浮标,然后对它们进行相等测试。提升是函数编程中monads上的常见操作。
明显简化了,只有两个参数都是Some
-cases时,我们才运行定制测试。通过对已区分的工会案例进行模式匹配,可以轻松实现这一点。
let eps = 1e-7 // or whatever is sensible in your domain
let equalityCompareFloatOption x y =
match x, y with
| Some x', Some y' -> abs(x' - y') < eps
| _ -> x = y
// val equalityCompareFloatOption : x:float option -> y:float option -> bool
equalityCompareFloatOption
(Seq.average[5.8;6.6;9.4;3.5;4.0] |> Some) (Some 5.86)
// val it : bool = true