Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0005781OCamlstandard librarypublic2012-10-09 18:252017-04-07 23:51
Assigned To 
PlatformOSOS Version
Product Version4.00.1 
Target VersionFixed in Version 
Summary0005781: min and max do not conform to IEEE 754 recommendations
Descriptionmin 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 *)

TagsNo tags attached.
Attached Files

- Relationships
related to 0004696closed min & max yield incorrect results with NaN 

-  Notes
gasche (administrator)
2012-10-10 10:40

The documentation highlights that `min` and `max` do not conform to the specification if one of the parameter is `nan` : [^]

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).
2012-10-10 11:19

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.
xleroy (administrator)
2012-10-14 10:29

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.
2012-10-15 09:38

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.
travm1 (reporter)
2017-04-07 23:51

Here is some more info about the IEEE 754 standard [^]

- Issue History
Date Modified Username Field Change
2012-10-09 18:25 user471 New Issue
2012-10-10 10:40 gasche Note Added: 0008233
2012-10-10 11:19 user471 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 user471 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
Powered by Mantis Bugtracker