Add shouldBeNear expectation#23
Conversation
|
Ping? |
|
Hey, sorry for the delay. For this to be useful this would at least need tests and more detailed documentation. Specifically I don't understand
|
There's no tests listed in the cabal file. I've found the tests in the repo and I'm adding tests, but how do I run them?
This is short circuit evaluation for the case where they are actually equal.
The code for the third case says |
|
I use ghci or sensei to run tests Sent from mobile
|
c5210c1 to
f8582f5
Compare
|
Tests are running on Travis now. Can you rebase on current I also wouldn't mind if you remove some of the code duplication, e.g. by factoring common stuff out into a Then I would love to discuss the actual stuff, that is the formula and the chosen value for epsilon. |
dec8922 to
8e4cc5a
Compare
|
Ok, the build has passed. Since the current code uses guards, its not possible to refactor common code into a |
|
I think you can use a where clause with guards, no? Sent from mobile
|
|
It works! Fixed, rebased and pushed. |
e43ce35 to
69bfa94
Compare
|
For some reason I couldn't get one the tests working with ghc 7.10 even though it passed on all the other versions. |
| src | ||
| ghc-options: -Wall | ||
| if impl(ghc >= 8.0) | ||
| ghc-options: -fno-warn-redundant-constraints |
There was a problem hiding this comment.
I fixed this on master, so this is no longer necessary.
263f489 to
4c7b60b
Compare
| -- If they actually are exactly equal we're done. | ||
| | actual == expected = reportFail (actual == expected) | ||
| -- If either input is zero, we check if the absolute difference is less than epsilon.. | ||
| | actual == 0 || expected == 0 = reportFail (abs (actual - expected) < 1e-15) |
There was a problem hiding this comment.
source code comments are an anti-pattern, rather than commenting make your code more expressive, e.g.
otherwise = reportFail (relativeDifference < epsilon)
| | actual == 0 || expected == 0 = reportFail (absDifference < epsilon) | ||
| | otherwise = reportFail (relativeDifference < epsilon) | ||
| where | ||
| epsilon = 1e-15 |
There was a problem hiding this comment.
for me it's much easier to work with code that does not use abbreviations, the reason for this is that I have to use speech recognition for programming due to RSI. for that reason I would much prefer absoluteDifference here
| actual `shouldBeNear` expected | ||
| -- Short circuit if they are actually equal. | ||
| | actual == expected = reportFail (actual == expected) | ||
| | actual == 0 || expected == 0 = reportFail (absoluteDifference < epsilon) |
There was a problem hiding this comment.
now finally regarding the interesting stuff, the formula, looking at the following example
x `shouldBeNear` 1e-300
I haven't tried, but what happens if x is
0.9e-3000
would (1) fail and (2) pass?
should we always normalize against the expected value instead?
actual `shouldBeNear` expected
| delta < epsilon = return ()
| otherwise = actual `shouldBe` expected
where
epsilon = 1e-15
absoluteDifference = abs (expected - actual)
relativeDifference = absoluteDifference / abs expected
delta
| expected == 0 = absoluteDifference
| otherwise = relativeDifference
There was a problem hiding this comment.
I haven't tried, but what happens if x is
0.9e-3000would (1) fail and (2) pass?
That is what currently happens, and I agree, at first sight, doesn't make much sense, but this is the usual recommended way to compare floating point numbers.
However, now that I think about it,
1e-300 `shouldBeNear` 0.0
should pass (because actual is close to expected), but I think maybe
0.0 `shouldBeNear` 1e-300
should fail.
Let me think about this some more.
There was a problem hiding this comment.
I have encoded my expectations in the tests.
Comparing floating point numbers for equalty is a bad idea. Instead they should tested to see if they are close enough to one another.
|
@sol Does this seem ok? |
| absoluteDifference = abs (expected - actual) | ||
| relativeDifference = absoluteDifference / (abs actual + abs expected) | ||
| reportFail = | ||
| expectTrue ("expected: " ++ show expected ++ "\n but got: " ++ show actual) |
There was a problem hiding this comment.
+1 on this change BTW!
Wouldn't it be nicer to report things like expected 123 ± 1% but got 125 or similar, as the expectation is of it being within a tolerance of the value not being the value?
|
@erikd is this still a valid approach or have you found a different way to tackle comparing Doubles? |
|
@istathar I stopped using |
Comparing floating point numbers for equalty is a bad idea. Instead
they should tested to see if they are close enough to one another.