为什么我不能在标准 ML 中比较实数? [英] Why can't I compare reals in Standard ML?

查看:11
本文介绍了为什么我不能在标准 ML 中比较实数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  1. 为什么 1.0 = 2.0 不起作用?real 不是相等类型吗?

  1. Why doesn't 1.0 = 2.0 work? Isn't real an equality type?

它给出了错误:

Error: operator and operand don't agree [equality type required]
  operator domain: ''Z * ''Z
  operand:         real * real
  in expression:
    1.0 = 2.0

  • 为什么模式中的实数不能这样工作?

  • Why won't reals in patterns work like so?

    fun fact 0.0 = 1.0
      | fact x = x * fact (x - 1.0)
    

    它给出了错误:

    Error: syntax error: inserting  EQUALOP
    

  • 推荐答案

    为什么 1.0 = 2.0 不起作用?real 不是相等类型吗?

    Why doesn't 1.0 = 2.0 work? Isn't real an equality type?

    没有.类型变量''Z表示=的操作数必须有相等类型.

    No. The type variable ''Z indicates that the operands of = must have equality types.

    为什么模式中的实数不起作用 [...]?

    Why won't reals in patterns work [...]?

    模式匹配隐含地依赖于相等性测试.神秘的错误消息 syntax error: inserting EQUALOP 表明 SML/NJ 解析器不允许在预期模式的地方使用浮点文字,因此阻止了程序员接收更有意义的类型错误.

    Pattern matching relies implicitly on testing for equality. The cryptic error message syntax error: inserting EQUALOP indicates that the SML/NJ parser does not allow for floating-point literals where a pattern is expected, and so the programmer is prevented from receiving a more meaningful type error.

    详细说明,

    来自 http://www.smlnj.org/doc/FAQ/faq.txt:

    问:real 是相等类型吗?

    Q: Is real an equality type?

    答:它在 SML '90 和 SML/NJ 0.93 中,但不在 SML '97 和 SML/NJ 110 中.所以 1.0 = 1.0 将导致类型错误,因为="要求具有相等性的参数类型.此外,真正的文字不能在模式中使用.

    A: It was in SML '90 and SML/NJ 0.93, but it is not in SML '97 and SML/NJ 110. So 1.0 = 1.0 will cause a type error because "=" demands arguments that have an equality type. Also, real literals cannot be used in patterns.

    来自 http://mlton.org/PolymorphicEquality:

    一种无法比拟的地面类型是真实的.因此,13.0 = 14.0 类型不正确.可以使用 Real.== 来比较实数是否相等,但要注意这与多态相等具有不同的代数属性.

    The one ground type that can not be compared is real. So, 13.0 = 14.0 is not type correct. One can use Real.== to compare reals for equality, but beware that this has different algebraic properties than polymorphic equality.

    例如,Real.== (0.1 + 0.2, 0.3)false.

    来自 http://sml-family.org/Basis/real.html:

    确定 real 是否应该是一个相等类型,如果是,那么相等的含义是什么,也是有问题的.IEEE 指定在比较中忽略零符号,并且如果任一参数为 NaN,则相等性评估为 false.

    Deciding if real should be an equality type, and if so, what should equality mean, was also problematic. IEEE specifies that the sign of zeros be ignored in comparisons, and that equality evaluate to false if either argument is NaN.

    这些限制令 S​​ML 程序员感到不安.前者意味着 0 = ~0 为真,而 r/0 = r/~0 为假.后者意味着诸如 r = r 是错误的异常,或者对于参考单元 rr,我们可以有 rr = rr 但没有 !rr = !rr.我们接受零的无符号比较,但认为应该保留等价、结构等价以及 <> 而不是 o = 的等价性的反身性质.

    These constraints are disturbing to the SML programmer. The former implies that 0 = ~0 is true while r/0 = r/~0 is false. The latter implies such anomalies as r = r is false, or that, for a ref cell rr, we could have rr = rr but not have !rr = !rr. We accepted the unsigned comparison of zeros, but felt that the reflexive property of equality, structural equality, and the equivalence of <> and not o = ought to be preserved.

    简短版本:不要使用相等来比较实数.执行epsilon 测试.我建议阅读关于 http://floating-point-gui.de/errors/comparison 的文章.总结:

    The short version: Don't compare reals using equality. Perform an epsilon test. I would recommend reading the article on http://floating-point-gui.de/errors/comparison. In summary:

    • 不要检查实数是否相同,但如果差异很小.

    • Don't check if reals are the same, but if the difference is very small.

    与差异 (delta) 进行比较的误差范围通常称为 epsilon.

    The error margin that the difference (delta) is compared to is often called epsilon.

    不要将差异与固定的epsilon进行比较:

    Don't compare the difference against a fixed epsilon:

    fun nearlyEqual (a, b, eps) = Real.abs (a-b) < eps
    

  • 不要只比较 relativeepsilon 的差异:

    fun nearlyEqual (a, b, eps) = abs ((a-b)/b) < eps
    

  • 注意极端情况:

  • Look out for edge cases:

    • b = 0.0 时,它会引发 Div.(切换 ab 提供对称的边缘情况.)

    • When b = 0.0 it raises Div. (Switching a and b provides a symmetric edge case.)

    ab 在零的对边时,它返回 false,即使它们是最小的非零个数字.

    When a and b are on opposite sides of zero it returns false even when they’re the smallest possible non-zero numbers.

    结果不可交换.在某些情况下,nearlyEqual (a, b, eps) 给出的结果与 nearlyEqual (b, a, eps) 不同.

    The result is not commutative. There are cases where nearlyEqual (a, b, eps) does not give the same result as nearlyEqual (b, a, eps).

    该指南提供了一个通用的解决方案;翻译成标准 ML 这看起来像:

    The guide provides a generic solution; translated to Standard ML this looks like:

    fun nearlyEqual (a, b, eps) =
        let val absA = Real.abs a
            val absB = Real.abs b
            val diff = Real.abs (a - b)
        in Real.== (a, b) orelse
         ( if Real.== (a, 0.0) orelse
              Real.== (b, 0.0) orelse
              diff < Real.minNormalPos
           then diff < eps * Real.minNormalPos
           else diff / Real.min (absA + absB, Real.maxFinite) < eps )
        end
    

    它继续警告一些边缘情况:

    And it continues to warn of some edge cases:

    在某些情况下,上述方法仍然会产生意想不到的结果(特别是,当一个值接近零时比恰好为零时要严格得多),并且它被开发通过的一些测试可能指定了以下行为不适用于某些应用程序.在使用它之前,请确保它适合您的应用程序!

    There are some cases where the method above still produces unexpected results (in particular, it’s much stricter when one value is nearly zero than when it is exactly zero), and some of the tests it was developed to pass probably specify behaviour that is not appropriate for some applications. Before using it, make sure it’s appropriate for your application!

    这篇关于为什么我不能在标准 ML 中比较实数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆