|Anonymous | Login | Signup for a new account||2017-08-23 19:41 CEST|
|Main | My View | View Issues | Change Log | Roadmap|
|View Issue Details|
|ID||Project||Category||View Status||Date Submitted||Last Update|
|0005781||OCaml||standard library||public||2012-10-09 18:25||2017-04-07 23:51|
|Target Version||Fixed in Version|
|Summary||0005781: min and max do not conform to IEEE 754 recommendations|
|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);;
- : float = -0. (* wrong *)
# max nan infinity;;
- : float = infinity (* correct *)
# max infinity nan;;
- : float = nan (* wrong: should be infinity (!) according to IEEE 754 since max(infinity, anything) gives infinity for any regular number *)
|Tags||No tags attached.|
The documentation highlights that `min` and `max` do not conform to the specification if one of the parameter is `nan` : http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html#VALmin [^]
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).
Sebastien Furic (reporter)
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.
Notice that the warning in the documentation is not sufficient: as suggested by my examples, we currently have situations where f(min(x, y)) > f(max(x, y)) where f is an increasing function (for instance copysign 1.0). The warning should also mention the sign of 0.0 as a possible cause of unexpected behavior.
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 PR#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.
Sebastien Furic (reporter)
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?
I forgot the "min and max of structure" feature of Ocaml and I understand that it is an issue as far as NaN is concerned.
Here is some more info about the IEEE 754 standard
|2012-10-09 18:25||Sebastien Furic||New Issue|
|2012-10-10 10:40||gasche||Note Added: 0008233|
|2012-10-10 11:19||Sebastien Furic||Note Added: 0008235|
|2012-10-14 09:58||xleroy||Relationship added||related to 0004696|
|2012-10-14 10:29||xleroy||Note Added: 0008253|
|2012-10-14 10:29||xleroy||Severity||major => feature|
|2012-10-14 10:29||xleroy||Status||new => resolved|
|2012-10-14 10:29||xleroy||Resolution||open => suspended|
|2012-10-15 09:38||Sebastien Furic||Note Added: 0008254|
|2017-02-23 16:43||doligez||Category||OCaml standard library => standard library|
|2017-04-07 23:51||travm1||Note Added: 0017728|
|Copyright © 2000 - 2011 MantisBT Group|