haskell — средняя ошибка с плавающей запятой с использованием QuickCheck

Я использую QuickCheck-2.5.1.1 для контроля качества. Я тестирую две чистые функции gold :: a -> Float и f :: a -> Float, где a экземпляров Произвольно.

Здесь gold — эталонный расчет, а f — вариант, который я оптимизирую.

На сегодняшний день в большинстве моих тестов с использованием quickcheck использовались такие тесты, как \a -> abs (gold a - f a) < 0.0001.

Тем не менее, я хотел бы собрать статистику вместе с проверкой порога, поскольку знание средней ошибки и стандартного отклонения полезно для управления моим дизайном.

Есть ли способ использовать QuickCheck для сбора такой статистики?


Конкретный пример

Чтобы привести конкретный пример того, что я ищу, предположим, что у меня есть следующие две функции для аппроксимации квадратных корней:

-- Heron's method
heron :: Float -> Float
heron x = heron' 5 1
    where
      heron' n est
          | n > 0 = heron' (n-1) $ (est + (x/est)) / 2
          | otherwise = est

-- Fifth order Maclaurin series expansion
maclaurin :: Float -> Float
maclaurin x = 1 + (1/2) * (x - 1) - (1/8)*(x - 1)^2
                + (1/16)*(x - 1)^3 - (5/128)*(x - 1)^4
                + (7/256)*(x - 1)^5

Тестом для этого может быть:

test = quickCheck
       $ forAll (choose (1,2))
       $ \x -> abs (heron x - maclaurin x) < 0.02

Так что я хотел бы знать, как побочный эффект теста, статистику по abs (heron x - maclaurin x) (например, среднее значение и стандартное отклонение).


person Matt W-D    schedule 12.03.2013    source источник
comment
Во-первых, я ожидаю, что вам нужно контролировать распределение ввода «а»? Как вы это делаете сейчас?   -  person Chris Kuklewicz    schedule 12.03.2013
comment
@ChrisKuklewicz: я генерирую случайную древовидную структуру. Это довольно сложно, и это не совсем та проблема, о которой я беспокоюсь. Я изменю свой первоначальный вопрос, чтобы привести конкретный пример того, что я ищу.   -  person Matt W-D    schedule 13.03.2013
comment
Не могли бы вы объяснить, почему у вас не работают стандартные механизмы быстрой проверки (например, ярлык и т. д.)?   -  person Ingo    schedule 13.03.2013
comment
Как говорит @Ingo, вы можете объединять результаты, преобразовывать их в строки и использовать «метку».   -  person Chris Kuklewicz    schedule 14.03.2013


Ответы (1)


Благодаря комментариям Криса Куклевича и Инго я придумал следующее, которое собирает статистику, которую я хочу в моем примере:

resultToWeightList :: Result -> [(Double,Int)]
resultToWeightList r = [ (read s, n) | (s,n) <- labels r]

weightListMuSigma :: [(Double,Int)] -> (Double,Double)
weightListMuSigma wlst = (mu,sigma)  
  where 
    (weightSum,weightSqrSum,entryCount) = foldl addEntry (0,0,0) wlst
    addEntry (s,s2,c) (v,w) = (s + (v * w'), s2 + (v**2 * w'), c + w)
      where w' = fromIntegral w
    entryCount' = fromIntegral entryCount
    mu = weightSum / entryCount'
    var = weightSqrSum / entryCount' - mu**2
    sigma = sqrt var

quietCheckResult :: Testable prop => prop -> IO Result
quietCheckResult p = quickCheckWithResult args p
  where args = stdArgs { chatty = False }

test :: IO ()
test = do { r <- quietCheckResult $ forAll (choose (1,2)) test'
          ; let wlst = resultToWeightList r
          ; let (mu,sigma) = weightListMuSigma wlst 
          ; putStrLn $ "Average: " ++ show mu
          ; putStrLn $ "Standard Deviation: " ++ show sigma
          }
   where
     test' x = collect err (err < 0.1)
       where err = abs $ heron x - maclaurin x
person Matt W-D    schedule 14.03.2013