Bug 10448 – min and max are not NaN aware

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-06-22T12:48:40Z
Last change time
2019-10-21T22:29:13Z
Keywords
pull
Assigned to
No Owner
Creator
monarchdodra

Comments

Comment #0 by monarchdodra — 2013-06-22T12:48:40Z
(and so are probably minCount, minPos, or mostly everything else that is related to opCmp). From the discussion https://github.com/D-Programming-Language/phobos/pull/1360 : min(0, float.nan); //Yields 0 max(0, float.nan); //Yields 0 min(float.nan, 0); //Yields float.nan max(float.nan, 0); //Yields float.nan Not sure what the correct solution is: Throwing an exception on NaN might be too expensive? How about an assert, combined with an explicit: "Passing nan is an ERROR", and let the user decide if/ifnot to pay for the check?
Comment #1 by thelastmammoth — 2013-06-22T13:13:06Z
(In reply to comment #0) > (and so are probably minCount, minPos, or mostly everything else that is > related to opCmp). > > From the discussion https://github.com/D-Programming-Language/phobos/pull/1360 > : > min(0, float.nan); //Yields 0 > max(0, float.nan); //Yields 0 > min(float.nan, 0); //Yields float.nan > max(float.nan, 0); //Yields float.nan > > Not sure what the correct solution is: Throwing an exception on NaN might be > too expensive? How about an assert, combined with an explicit: "Passing nan is > an ERROR", and let the user decide if/ifnot to pay for the check? I don't see why one would throw on nan, and it would be expensive. I believe the accepted convention is that nan is treated as missing data for min/max, so that min(0, float.nan); //Yields 0 max(0, float.nan); //Yields 0 min(float.nan, 0); //Yields 0 max(float.nan, 0); //Yields 0 related discussion: http://bytes.com/topic/c/answers/528404-max-nan-0-should-nan matlab does it that way btw.
Comment #2 by simen.kjaras — 2013-06-22T13:16:30Z
Exactly. See documentation of fmax at http://man7.org/linux/man-pages/man3/fmax.3.html Specifically: If one argument is a NaN, the other argument is returned. If both arguments are NaN, a NaN is returned.
Comment #3 by andrej.mitrovich — 2013-06-22T13:31:19Z
Then it needs to be documented in Phobos, and this fixed: min(0, float.nan); //Yields 0 min(float.nan, 0); //Yields float.nan (should be 0 then?)
Comment #4 by bearophile_hugs — 2013-06-22T13:39:58Z
(In reply to comment #2) > Exactly. See documentation of fmax at > http://man7.org/linux/man-pages/man3/fmax.3.html > > Specifically: > If one argument is a NaN, the other argument is returned. > > If both arguments are NaN, a NaN is returned. Isn't it better for min(0, float.nan) to be NaN, just as max(0, float.nan) ?
Comment #5 by monarchdodra — 2013-06-22T14:47:00Z
(In reply to comment #4) > (In reply to comment #2) > > Exactly. See documentation of fmax at > > http://man7.org/linux/man-pages/man3/fmax.3.html > > > > Specifically: > > If one argument is a NaN, the other argument is returned. > > > > If both arguments are NaN, a NaN is returned. > > Isn't it better for min(0, float.nan) to be NaN, just as max(0, float.nan) ? Yeah, that sounds like the better behavior: *anything* and nan is always nan.
Comment #6 by thelastmammoth — 2013-06-22T14:49:52Z
(In reply to comment #5) > (In reply to comment #4) > > (In reply to comment #2) > > > Exactly. See documentation of fmax at > > > http://man7.org/linux/man-pages/man3/fmax.3.html > > > > > > Specifically: > > > If one argument is a NaN, the other argument is returned. > > > > > > If both arguments are NaN, a NaN is returned. > > > > Isn't it better for min(0, float.nan) to be NaN, just as max(0, float.nan) ? > > Yeah, that sounds like the better behavior: *anything* and nan is always nan. that would indeed seem more logical, although: * it differs from standard practice * it incurs additional cost, compared to : return a<b?a:b; because you'd have to check for isNan
Comment #7 by monarchdodra — 2013-06-22T14:59:55Z
(In reply to comment #6) > (In reply to comment #5) > > (In reply to comment #4) > > > (In reply to comment #2) > > > > Exactly. See documentation of fmax at > > > > http://man7.org/linux/man-pages/man3/fmax.3.html > > > > > > > > Specifically: > > > > If one argument is a NaN, the other argument is returned. > > > > > > > > If both arguments are NaN, a NaN is returned. > > > > > > Isn't it better for min(0, float.nan) to be NaN, just as max(0, float.nan) ? > > > > Yeah, that sounds like the better behavior: *anything* and nan is always nan. > > that would indeed seem more logical, although: > > * it differs from standard practice > * it incurs additional cost, compared to : return a<b?a:b; because you'd have > to check for isNan "return a<b?a:b;" doesn't work: you'd have to check for nan regardless of which you return.
Comment #8 by thelastmammoth — 2013-06-22T15:11:43Z
(In reply to comment #7) > (In reply to comment #6) > > (In reply to comment #5) > > > (In reply to comment #4) > > > > (In reply to comment #2) > > > > > Exactly. See documentation of fmax at > > > > > http://man7.org/linux/man-pages/man3/fmax.3.html > > > > > > > > > > Specifically: > > > > > If one argument is a NaN, the other argument is returned. > > > > > > > > > > If both arguments are NaN, a NaN is returned. > > > > > > > > Isn't it better for min(0, float.nan) to be NaN, just as max(0, float.nan) ? > > > > > > Yeah, that sounds like the better behavior: *anything* and nan is always nan. > > > > that would indeed seem more logical, although: > > > > * it differs from standard practice > > * it incurs additional cost, compared to : return a<b?a:b; because you'd have > > to check for isNan > > "return a<b?a:b;" doesn't work: you'd have to check for nan regardless of which > you return. my bad, which is probably why the current min is buggy. In that case since there's no penalty might as well do the safest thing, ie returning nan, and provide a minIgnoresNan to do the 'standard behavior', which will return 0 instead of nan.
Comment #9 by code — 2016-05-15T18:48:51Z
There is no clearly "correct" way here, see the PR discussion on GitHub: https://github.com/dlang/phobos/pull/4316#issuecomment-219301946
Comment #10 by ilyayaroshenko — 2016-08-02T20:07:24Z
Default behavior should be that min/max be translated to the single assembler instruction, which can be vectorized. Compiler may have intrinsics for min/max and we should just use them. See also https://llvm.org/bugs/show_bug.cgi?id=24314
Comment #11 by dlang-bugzilla — 2017-07-05T20:10:12Z
FWIW, after https://github.com/dlang/phobos/pull/2198, the output changes to: nanF 0.00000F 0.00000F nanF Still looks broken, but in a different way.
Comment #12 by dlang-bot — 2019-09-11T12:28:25Z
@crocopaw created dlang/phobos pull request #7181 "Fix Issue 10448 - min and max are not NaN aware" fixing this issue: - Fix Issue 10448 - min and max are not NaN aware https://github.com/dlang/phobos/pull/7181
Comment #13 by dlang — 2019-09-11T12:31:08Z
As experts do not agree on the prefered result I think it's best to document, that NaNs will result in undefined behaviour. See https://github.com/dlang/phobos/pull/7181 for more details.
Comment #14 by dlang-bot — 2019-10-21T09:49:07Z
@berni44 created dlang/phobos pull request #7240 "Fix Issue 10448 - min and max are not NaN aware" fixing this issue: - Fix Issue 10448 - min and max are not NaN aware https://github.com/dlang/phobos/pull/7240
Comment #15 by dlang-bot — 2019-10-21T22:29:13Z
dlang/phobos pull request #7240 "Fix Issue 10448 - min and max are not NaN aware" was merged into master: - 0320d88c3aecb5af38b68fc2efcbf661d07190a1 by Bernhard Seckinger: Fix Issue 10448 - min and max are not NaN aware https://github.com/dlang/phobos/pull/7240