简体   繁体   English

使用 HUnit 在 Doubles 上测试 haskell 相等性?

[英]Testing haskell equality on Doubles with HUnit?

Does HUnit have some way of doing approximate equalities? HUnit 有什么方法可以做近似等式吗? Clearly, this fails:显然,这失败了:

test1 = TestCase (assertEqual "Should equal" (get_scores) [(0.3, 0.3), (0.6, 0.36), (1.0, 0.3399999)])

For floating point approximate comparison, there's a library with some nice utils: 对于浮点近似比较,有一个带有一些不错的工具的库:

http://hackage.haskell.org/package/ieee754 http://hackage.haskell.org/package/ieee754

Since this question was first asked, the HUnit-approx package has been released.自从第一次提出这个问题以来, HUnit-approx软件包已经发布。

It uses an implicit variable, epsilon , and an approximate equality operator, ~?~ , instead of ~=?它使用隐式变量epsilon和近似相等运算符~?~代替~=? . .

A short example:一个简短的例子:

tweak :: Float -> Float
tweak x = x * 1.0001

egApproxTest  = let ?epsilon = 0.01 in
    [ "strictEqual" ~: 0 ~=? tweak 0,
      "approxEqual" ~: 2 ~?~ tweak 2 ]

Note: I don't know if there's a correct/official/accepted way to do this. 注意:我不知道是否有正确/官方/可接受的方式来执行此操作。


Here's the source code for assertEqual : 这是 assertEqual的源代码:

assertEqual :: (Eq a, Show a) => String -- ^ The message prefix 
                              -> a      -- ^ The expected value 
                              -> a      -- ^ The actual value
                              -> Assertion
assertEqual preface expected actual =
  unless (actual == expected) (assertFailure msg)
 where msg = (if null preface then "" else preface ++ "\n") ++
             "expected: " ++ show expected ++ "\n but got: " ++ show actual

Based on that and on JUnit's function for testing double equality , we could create our own in the same style: 基于此以及基于JUnit的用于测试双重相等的功能 ,我们可以使用相同的样式创建自己的样式:

import Control.Monad (unless)

assertEquals ::   String  -- ^ The message prefix
               -> Double  -- ^ The maximum difference between expected and actual
               -> Double  -- ^ The expected value
               -> Double  -- ^ The actual value
               -> Assertion
assertEquals preface delta expected actual = 
  unless (abs (expected - actual) < delta) (assertFailure msg)
 where msg = ... same as above ...

For my purposes, this helper function worked well enough: 就我的目的而言,此辅助功能运行良好:

assertFloatEqual text a b = 
  assertEqual text (take 6 (show a)) (take 6 (show b))

I made my data type an instance of equal with code there to use 2 decimal places. 我将数据类型设置为等于代码的实例,以使用2个小数位。 Here is an example using a cartesian point: 这是使用笛卡尔点的示例:

data Point =  Point { x_axis :: Double, y_axis :: Double, z_axis :: Double } 
              deriving (Show)

Instance of equal 相等的实例

In order to avoid double rounding errors and trig errors which cause the same point, and thus CornerPoints, to be /= due to tiny differences, give it a range of .01 , and still allow the points to be equal. 为了避免由于相同的微小差异而导致导致相同点(因此,CornerPoints)为/=两次舍入误差和触发误差,请将其范围设置为.01 ,并且仍然允许这些点相等。

axisEqual :: (Eq a, Num a, Ord a, Fractional a) => a -> a -> Bool

axisEqual  a b
  | (abs (a - b)) <= 0.011 = True
  | otherwise      = False

instance Eq Point where

  Point x y z == Point xa ya za
    | (axisEqual x xa) && (axisEqual y ya)  &&(axisEqual z za) = True 
    | otherwise = False

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM