Closed splace closed 7 years ago
Is the exercise based on this fallacy or are the tests just covering for a limitation?
Because it is a fundamental principle, should we almost assume that fundamentally most users of the exercises will have come across this?
In the Readme for the exercise, is there a teaching example that reinforces this? And if so, would you, @splace, be up for a pull request to help correct it?
The exercise is meant to be an excuse to give people programming practice, not a method of teaching mathematics.
We could deprecate the exercise if it's a problem.
I agree that it is desirable for Exercism to try to push students toward good practices.
Since the problem here is with precision, sounds like there's no problem with the integer cases. Further, that there would be no problem if the implementing languages used their respective data type for rational numbers (if it exists), rather than floating-point numbers.
So then, if it is agreed that this is an issue, the first step to correcting it would be to remove https://github.com/exercism/x-common/blob/master/exercises/triangle/canonical-data.json#L55 and https://github.com/exercism/x-common/blob/master/exercises/triangle/canonical-data.json#L106 and https://github.com/exercism/x-common/blob/master/exercises/triangle/canonical-data.json#L145. The possible next step is to add an equivalent test using rationals, or decide that such a one is unnecessary.
I don't think going as far as to deprecate the exercise is necessary (but I'm not going to stop anyone!).
A caution that there will inevitably be other exercises that deal with floating point. For example, https://github.com/exercism/x-common/blob/master/exercises/space-age/canonical-data.json . At least there we aren't asking students to do the floating-point comparison; the test suites are doing it.
I'd rather add potentially problematic test cases for students to try to solve than deprecate the whole exercise, or any test just because it has floating points in it. Some ideas for how to construct them could be gathered from here:
http://0.30000000000000004.com
One simple one would be that an input of sides lengths 0.1
, 0.2
, and 0.3
should be a recognized as a non-triangle.
in the example the test input coordinates have limited precision so it can work.
This is true.
but it gives people a false idea, that it will always work,
This is not.
The triangle exercise makes no claims at all about floating point precision.
If this is a concern to you I suggest constructing a separate problem that specifically deals with the complexities of floating point.
(Aside: Are you able to provide a floating point test case that would be problematic for the triangle
exercise? I am unable to think of one.)
I submitted this Ruby implementation:
http://exercism.io/submissions/31964a09ddc141adbac5e0f206cc284a
which fails the following added test:
def test_scalene_triagle_with_problematic_floats
triangle = Triangle.new([0.1, 0.2, 0.3])
refute triangle.scalene?, "Expected 'false', triangle is not scalene--not a triangle."
end
Some questions I think this raises:
Thanks for providing a test case we can discuss :heart:
is this a fair test for the Triangle exercise?
No.
See: https://github.com/exercism/x-common/blob/master/exercises/triangle/canonical-data.json#L5
should new students of a language be expected to solve this?
No, and they are not currently expected to.
how should new students be exposed to the vagueries of their language's implementation of floating points?
Via a specific floating point problem, which is yet to be written.
telling if a triangle has exactly zero area suffers from the same issue.
so you can not 'exclude' them, simply because you can not reliably detect them.
telling if a triangle has exactly zero area suffers from the same issue. so you can not 'exclude' them, simply because you can not reliably detect them.
This problem is not about determining if 3 side lengths construct a triangle.
It is about determining what type a triangle is. As such, it is reasonable that all triangles provided as test input will be valid and reliably computable triangles.
Do you have a specific change to propose?
It is about determining what type a triangle is. As such, it is reasonable that all triangles provided as test input will be valid and reliably computable triangles.
so state; "only has to work on these test inputs"
Do you have a specific change to propose?
well since its a faulty 'concept' issue, my first through was remove it. but that seems harsh, since its just a basic example, and nobody learns anything.
so you could keep it and just add a large disclaimer, like: "assume for this example that calculations are infinitely precise" followed by a link to an explanation of rounding issues.
but then having to have these kinds of caveats tends to indicate the example has advanced issues not appropriate for this level.
or...
moving away from triangles, making it just a count of how many numbers (integers), from three, are the same.
like this...
https://play.golang.org/p/SWMfDXo2vM
to get something more like the origin, this could be wrapped in a function that clearly shows the rounding assumption being made etc.
I've been thinking about this off-and-on, and I'm more-and-more of the opinion the exercise is fine the way it is, basically for the reasons @Insti brought up above.
Thank you @Insti for bringing up https://github.com/exercism/x-common/blob/master/exercises/triangle/canonical-data.json#L5 referring to #202. That was a good decision.
OK
the problem is hard to explain, but...
to always be able to determining if a triangle is equilateral requires infinite precision because its a euclidean definition, and computers cannot do that.
this general misunderstanding produces a lot of bugs in code.
understanding why this is, is a fundamental principle see; https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems
in the example the test input coordinates have limited precision so it can work, but it gives people a false idea, that it will always work, its a incorrect concept that teaching examples shouldn't be re-enforcing.