non*_*ont 1 haskell double-precision quickcheck repa
我写了一些使用repa 计算距离矩阵的代码:
distance :: Int -> Int -> Mat -> Double
distance aindx bindx arr = let a = slice arr (Any :. aindx :. All)
b = slice arr (Any :. bindx :. All)-
sqdiff = R.map (\x -> x*x) $ R.zipWith (-) a b
in sqrt $ sumAllS sqdiff
buildDistanceMatrix :: Mat -> Mat
buildDistanceMatrix m = let (Z :. height :. width) = R.extent m
cords = fromListUnboxed (Z :. (height * height) ) [ (x,y) | x <- [0..height-1], y <- [0..height-1]]
dist = R.smap (\(a,b) -> distance a b m) cords
dmat = R.reshape (Z :. height :. height ) dist
in R.computeS dmat
Run Code Online (Sandbox Code Playgroud)
它似乎工作.但后来我添加了一个QuickCheck:
prop_distmat :: Double -> Bool
prop_distmat d = let dvec = [d,0,0,0]
dmat = R.fromListUnboxed (Z :. (2::Int) :. (2::Int)) dvec
dist = buildDistanceMatrix dmat
in (R.toList dist) == [0.0, d, d, 0.0 ]
Run Code Online (Sandbox Code Playgroud)
换句话说,由距离D分开的两个点应该产生看起来像[0,D,D,0]的距离矩阵.在我的adhoc手动测试中,确实如此.但QuickCheck很快发现5.0e-324的距离产生的距离矩阵为[0,0,0,0]
distance matrix *** Failed! Falsifiable (after 2 tests and 1074 shrinks):
5.0e-324
Run Code Online (Sandbox Code Playgroud)
这只是因为双打的精确度?我是否需要钳制QuickCheck将发送的可能值?或者这是一个真正的错误?
您正在测试浮点数的相等性,通常应该避免这种情况(在任何语言中,这都不是特定于Haskell的).你也可以通过大双打来获得无限大的溢出效果.并且sqrt (x*x) == x即使对于那些没有溢出或下溢的双打,也不能保持一般性.所以你需要==用检查替换差异最多是一些合理的epsilon并限制可能的值(或检查属性中的溢出).