F#中带浮点(双型)的模式匹配

时间:2019-05-04 08:49:05

标签: f# floating-point pattern-matching double

谁能解释为什么F#在模式处理表达式中似乎不喜欢浮点数(Double类型)?

let intDiv x y =
    match x / y with
    | 5 -> printfn "Result was five - congrats"; 5
    | z -> printfn "Result was something else: %i" z; z

匹配int类型:按预期工作。

let floatDiv x y =
    match x / y with
    | nan      -> printfn "Homie, what did you even do?"; nan
    | infinity -> printfn "Wow, you got infinity!"; infinity
    | 5.0      -> printfn "Result was 5 - proud of you"; 5.0
    | z        -> printfn "Result was something else: %i" z; z

这里,匹配大小写nan每次都会匹配,并且编译器也会对此警告我-但是,它似乎也会返回正确的结果。我只希望它与最后一种情况z相匹配。

> floatDiv 10. 3.;;
Homie, what did you even do?
val it : float = 3.333333333

1 个答案:

答案 0 :(得分:2)

如您所见,<IfModule mod_rewrite.c> <IfModule mod_negotiation.c> Options -MultiViews </IfModule> RewriteEngine On AllowOverride All # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1 [L,R=301] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] # Handle Authorization Header RewriteCond %{HTTP:Authorization} . RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] </IfModule> nan在这里被视为标识符,并且值绑定到它们。

如果检查F#规范:https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf

第7章(第115页)说infinity表达式是一种模式。

第4章(第36页)说const包括const

第3章(第29页)说ieee64ieee64或整数后跟float

在示例位置,我们找到了LF的定义。

float

此定义仅涵盖123、3.14、1E99等情况。它既不包含无穷也不包含nan。

因此,按照规范,上述行为是预期的。应该改变吗?也许但涉及到更新语言以将nan和infinity包含为float常量表达式的一部分。由于token float = digit+ . digit* digit+ (. digit* )? (e|E) (+|-)? digit+ 确实包含这些值,因此我认为它应该成为常量表达式的一部分是有意义的。

但是,更改可能有风险,因为旧代码ieee中的突然更改意味着对方法的引用,更改将是浮点文字。也许有人用nan作为函数名?现在那样会崩溃,因为这就像给一个函数命名:nan

如@Foole所述,您可以使用活动模式来解决此问题。

0

将浮点数与特定数字进行比较总是有点“风险”,因为浮点数的性质通常只是一个近似的答案。通常,将结果与公差范围进行比较。

此外; nan使许多开发人员感到困惑,因为涉及nan的大多数比较都是错误的。

// 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"