-
Notifications
You must be signed in to change notification settings - Fork 137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LD feature newtry #68
LD feature newtry #68
Conversation
…s selection, not so easy with Lua patterns
…s JITed version (e.g. num = 100). Also useful (with lower num, e.g. num = 4) to check reference transparency of tests, a key property of unit tests.
…sertIf and assertNotIf respectively (and variant added)
…r testing numeric codes, still keep EPSILON as default margin to help common cases, leave user margin untouched if provided (main concern!)
Thank you, this looks much cleaner now! Side note: This PR has replaced / superseded #66, while the previous discussion there is still relevant. (Readers might want to cross-check it to get the complete picture.) |
Best,
|
For the assertTrue / assertFalse, after some more thinking, I agree with Laurent. I also had the case of incorrect catch of nil through assertFalse which prevented me to find a bug in my code. Strictness is a key feature of unit testing. So let's go with strict. I don't like the assertIf name for the old behavior; the name does not carry enough the functionality. assertNilOrFalse looks better as a name and carry the meaning correctly. |
For merging the changes, I have my internal policy of merging functionality along with unit-test that validate it. This way, I can ensure that core luaunit is always as stable as possible. So, either Laurent, you add more unit-tests for the functionality which you have added, or you leave it as it is and I will write the unit-test myself. I already appreciate the effort you have been putting into contributing to luaunit so I am hesitant to ask for more... |
Side note: If we aim to support multiple numeric precisions, it might become necessary to 'dynamically' select EPSILON depending on the expected magnitude of rounding errors - see e.g. n1tehawk@fc8ec20. A value that is suitable for Lua's default "double" precision may be useless (too small to compensate for errors) with "single" precision. |
On 27 Jul 2016, at 09:03, NiteHawk notifications@github.com wrote:
Why not simply use: single precision (if any): M.EPSILON = 2^4 * 2^-23 ~ 2e-6 Larger epsilon may be not be strict enough to detect bugs, even in simple cases… If precision error reach this level of EPSILON, something wrong is going on and/or the test itself introduces enough uncertainty that the user must provide appropriate epsilon. For example: print((60-math.deg(math.pi/3))/2^-52) —> 32 Tells you that despite of its simplicity, radian to degree conversion is not accurate for 60 degrees (i.e. pi/3) and needs a margin of 32 * 2^-52 = 32 * DBL_EPSILON… Hiding this fact is not good for users, it is often better to give an opportunity to the users to understand what’s happening (and maybe learn something useful). Best, |
Hi,
Just to not confuse people with this example, what I wanted to say here is that assertAlmostEquals is using margin as an absolute error. The case above was an example to show that sometime (most of the time…) absolute error is not suitable and the user must 1) be aware (with not to lazy EPSILON), 2) use the appropriate error check, typically the relative error: ( 60-math.deg( math.pi/3))/2^-52 = 32 EPS the absolute error is proportional to angle (as expected), but the relative error is stable: ( 60/math.deg( math.pi/3)-1)/2^-52 = 1 EPS That is why personally, I prefer to explain than to hide the problem and keep the tests as strict as possible. There is no best EPSILON for absolute error, so I would even go for Best, |
Best, |
…lmostEquals expect(ed) 3 numbers from the beginning
I'm currently thinking about a (helper) function that could be used to specify the desired error "margin" (boundary), both as absolute value and 'relative' to the internal precision (in terms of ε). This function would handle the two optional parameters limit and epsilons from something like --[[ function to determine an error margin
`limit` represents an "absolute" boundary that should not be exceeded. For
user's convenience, it's possible to pass a non-numeric argument (boolean
`true`) to select M.EPSILON as the default margin.
`epsilons` is a multiplicative factor that specifies the value in terms of
"multiples of M.EPSILON". (This may be useful to express error margins relative
to the numeric precision that the underlying Lua implementation offers.)
If two parameters are specified, both will be interpreted as described above,
and then this function will select the smaller (absolute) value of the two,
i.e. the narrower margin. This reflects whatever condition of margin(limit, nil)
and margin(nil, epsilons) would be "more strict".
margin() 0
margin(2E-7) 2E-7
margin(2E-7, 3) math.min(2E-7, 3 * M.EPSILON)
margin(true) M.EPSILON
margin(nil, 1) M.EPSILON
margin(true, 0.5) math.min(M.EPSILON, 0.5 * M.EPSILON) = M.EPSILON / 2
]]
local function margin(limit, epsilons)
local function relaxedMin(a, b)
-- Return the minimum of (a, b), i.e. the smaller value between the two.
-- Either value may be `nil`, in that case the other is returned - if
-- both a and b are nil, the function will return nil too.
if a ~= nil then
if b == nil then
return a
end
if a < b then
return a
end
end
return b
end
if limit then
limit = tonumber(limit) or M.EPSILON
end
if epsilons then
epsilons = tonumber(epsilons)
or error("Malformed 'epsilons' parameter: " .. epsilons)
epsilons = epsilons * M.EPSILON
end
-- default value below open to debate: 0 or M.EPSILON ?
return relaxedMin(limit, epsilons) or 0
end Undoubtedly the function is to respect any user-provided zero value (one of your primary concerns), i.e. Regards, NiteHawk |
Regarding marginBoost, @ldeniau , you have convinced me that it should go away. For this assertAlmostEquals, we will face two kind of users :
LuaUnit itself can not pretend to solve all the problems related to computing errors. |
What we can do however is to provide explicit documentation support and link to further explanations. |
Philippe, regarding your remark in #77: I wanted to clarify on At that point in time the state of this pull request was unclear to me, and I didn't want to break the way LuaUnit is currently working. I'm fine with any further improvents of that function that we eventually come up with here. [EDIT] One way to achieve the desired "strictness" would be to change Regards, NiteHawk |
Hi, AFAICS, I don’t have remark in #77. Could you be more precise? Concerning EPSILON, and Margin boost, we already had lengthy discussion and my point of view was already clear enough. EPSILON as a default value when the user does not provide one is fine. Margin boost is an heresy and must absolutely be removed, because it hides bugs! Moreover, you will never be able to set Margin boost (or even Epsilon) for general use, so in all cases, it brings more problem than it solves. On the other hand, making assertAlmostEqual an equivalent to assertEqual with a user margin (or EPSILON if not provided) would be much more useful (and sharing the same underlying code). In many many tests, with have to loop over tables with assertAlmostEqual where assertEqual would nicely do the job (but without margin). Best,
|
I'm sorry, I addressed you by mistake instead of Philippe before editing my comment above. |
Let's summarize / cut down on the status of this PR: Half of the (12) commits above have already been integrated into master
The This leaves us with (only) the core changes made to Corresponding unit tests are here, and I'd also propose a change that outputs the actual numerical difference by which margin was exceeded (or missed) in the failure message, to avoid potential confusion of users: see here. Regards, NiteHawk |
Can we finalize this pull request somehow? @ldeniau I think the set of changes in master...n1tehawk:20161105_pull68 should contain anything that's left? If you're okay with that, I can create a corresponding PR; and (after it has been merged) this one could be closed... Regards, NiteHawk |
For me, all changes have been indeed integrated. I'll close it soon. |
The change that modifies almostEquals() to fully respect the user-provided margin (instead of silently adding |
Closing this PR. We will cherry-pick the count of assertions in another PR. |
[second attempt to make a clean pull request, hope it will be fine]
As discussed with Philippe Fremy by email, I do a pull request for features I needed and proved to be extremely useful to test codes, including LuaJIT itself and scientific codes.
Modified:
Added:
Typical use of added extensions assuming that TestPerf are performance tests (longer to run):
./luajit testsuite.lua -x TestPerf # only regression tests
./luajit testsuite.lua -p TestPerf # only performance tests
./luajit testsuite.lua -c 4 -x TestPerf # test referential transparency of regression tests
./luajit testsuite.lua -c 100 -x TestPerf # test JITed version of regression tests
Last use is essential to check consistency between interpreted and compiled code with LuaJIT. I found few bugs and inconsistencies with this feature!
Do not hesitate to ask me information to clarify any points, especially for the documentation. I have motivated all my proposal through email discussions with Philippe and NiteHawk. As a general comment, the philosophy of the proposal is to improve strictness of the unit tests (never relax it!) and flexibility of the framework (in that order).
Best,
Laurent.