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
min and max do not conform to IEEE 754 recommendations #5781
Comments
Comment author: @gasche The documentation highlights that I don't think we should make those generic functions any slower by adding tests for the floating-point case. It could make sense to provide floating-point-specific functions with the expected behavior (maybe in one of the extended libraries project, Batteries or Core). |
I would prefer the standard library to come with a correct version of min and max instead of one that breaks expected invariants with floats, especially since we are in a situation where a one-liner would anyway save programs whose performance suffers from a "too safe" definition of min and max. |
Comment author: @xavierleroy According to the latest (2008) version of the IEEE-754 standard (p. 19, functions minNum and maxNum), minNum x y and maxNum x y can return either x or y if x and y compare equal. So, max (-0.0) 0.0 = -0.0 is correct according to IEEE-754. If you don't agree with this behavior, you should take the issue with the IEEE-754 committee. Concerning NaN behavior, IEEE-754-2008 agrees with the behavior you expected (NaN, non-NaN -> non-NaN), which corresponds to the "NaN as missing data" view. Note that the other behavior (NaN, non-NaN -> NaN) was also requested (see #4696), as it makes more sense if we view NaN as an error that must propagate upwards. A problem with implementing the minNum/maxNum NaN behavior is that OCaml's min and max functions are polymorphic and apply at any type where generic comparison is defined. So, for example min (1.0, 2.0) (3.0, 0.0) = (1.0, 2.0) This raises the case, not covered by IEEE-754, where both arguments contain NaNs but are different: min (nan, 1.0) (1.0, nan) in which case there is no "best" choice of result. The closest we could get to the IEEE-754 behavior is to guarantee that if one argument contains a NaN and the other contains no NaNs, the latter is returned. Implementing this behavior on top of the current generic comparison operator would require two comparisons instead of one, and that's a big increase in running time because the generic comparison is quite slow. For all these reasons (run-time costs, polymorphism of min and max, lack of agreement whether min and max should be strict or lenient in NaN arguments), I think the current documented behavior of min and max wrt NaN is reasonable. |
Notice that I haven't said max (-0.0) 0.0 returning -0.0 is not IEEE-754-compliant (the name I gave to this issue was a bit misleading, sorry). BTW the same issue exists even for functions such as sqrt (although reasonable people would certainly expect its argument and result to be non-negative!). I would just have preferred Ocaml to adopt a robust behavior by avoiding breaking invariants such as the one I mentioned (since there is room for this case in IEEE-754). After all, correctness is the /raison d'être/ of OCaml, right? |
Comment author: travm1 Here is some more info about the IEEE 754 standard |
Original bug ID: 5781
Status: resolved (set by @xavierleroy on 2012-10-14T08:29:49Z)
Resolution: suspended
Priority: normal
Severity: feature
Version: 4.00.1
Category: standard library
Related to: #4696
Monitored by: mww @hcarty
Bug description
min and max functions are implemented this way in Pervasives:
let min x y = if x <= y then x else y
let max x y = if x >= y then x else y
This gives bad results with floating-point numbers:
max (-0.0) (0.0);;
max nan infinity;;
max infinity nan;;
etc.
The text was updated successfully, but these errors were encountered: