Aph*_*hex 4 floating-point double f# pattern-matching
谁能解释为什么 F# 似乎不喜欢模式处理表达式中的浮点数(Double 类型)?
\n\nlet intDiv x y =\n match x / y with\n | 5 -> printfn "Result was five - congrats"; 5\n | z -> printfn "Result was something else: %i" z; z\nRun Code Online (Sandbox Code Playgroud)\n\n匹配int类型:按预期工作。
let floatDiv x y =\n match x / y with\n | nan -> printfn "Homie, what did you even do?"; nan\n | infinity -> printfn "Wow, you got infinity!"; infinity\n | 5.0 -> printfn "Result was 5 - proud of you"; 5.0\n | z -> printfn "Result was something else: %i" z; z\nRun Code Online (Sandbox Code Playgroud)\n\nnan这里每次都会匹配匹配大小写,编译器也会警告我有关此\xe2\x80\x94的信息,但是,它似乎也会返回正确的结果。我只期望它与最后一个案例匹配z。
> floatDiv 10. 3.;;\nHomie, what did you even do?\nval it : float = 3.333333333\nRun Code Online (Sandbox Code Playgroud)\n
正如您所观察到的nan, 和infinity在这里被视为标识符,并且值与它们绑定。
如果检查 F# 规范:https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf
第 7 章(第 115 页)说const表达式是一种模式。
第 4 章(第 36 页)说 aconst包含ieee64.
第 3 章(第 29 页)说 aieee64是 afloat或后面跟着的整数LF
在示例位置我们找到 的定义float。
token float =
digit+ . digit*
digit+ (. digit* )? (e|E) (+|-)? digit+
Run Code Online (Sandbox Code Playgroud)
该定义仅涵盖 123、3.14、1E99 等情况。它不包括无穷大或 nan。
因此,根据规范,上述行为是预期的。是否应该改变?也许,但涉及更新语言以包含 nan 和无穷大作为 float 常量表达式的一部分。由于ieee确实包含这些值,所以我认为它应该是常量表达式的一部分。
但是,这种更改可能存在风险,因为旧代码中突然nan意味着对方法的引用,而更改后它将是浮点文字。也许有人使用 nan 作为函数名?现在会崩溃,因为这就像给一个函数命名:0。
正如@Foole 所提到的,您可以使用活动模式来解决这个问题。
// Define the Active Pattern
let (|Float|Infinity|NaN|) n =
if System.Double.IsPositiveInfinity n then Infinity true
elif System.Double.IsNegativeInfinity n then Infinity false
elif System.Double.IsNaN n then NaN
else Float n
// We can then use the Active Pattern as a "smart" pattern
let floatDiv x y =
match x / y with
| NaN -> printfn "Homie, what did you even do?"; nan
| Infinity _ -> printfn "Wow, you got infinity!"; infinity
| Float 5.0 -> printfn "Result was 5 - proud of you"; 5.0
| Float z -> printfn "Result was something else: %f" z; z
let run () =
floatDiv 1.0 2.0 |> printfn "%A"
floatDiv 5.0 1.0 |> printfn "%A"
floatDiv 1.0 0.0 |> printfn "%A"
floatDiv 0.0 0.0 |> printfn "%A"
Run Code Online (Sandbox Code Playgroud)
将浮点数与特定数字进行比较总是有点“冒险”,因为浮点数本质上通常只是一个近似答案。通常将结果与公差范围进行比较。
此外; nan 让许多开发人员感到困惑,因为大多数涉及 nan 的比较都是错误的。
1.0 < nan // false <-|
nan < 1.0 // false, <-| these inequalities can break balanced trees algorithms if you use float as a key and happen to insert a nan
nan = nan // false <-|
nan <> nan // true <-| perhaps also surprising?
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
742 次 |
| 最近记录: |