[ 
https://issues.apache.org/jira/browse/NUMBERS-77?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17329332#comment-17329332
 ] 

Alex Herbert commented on NUMBERS-77:
-------------------------------------

{quote}I think that there is a problem when {{0 < |a| < eps}}
{quote}
Good spot. It will return a and not 0.

Looking at Matt's example in AbstractHyperPlane then this is a case where -0.0 
should not return -1 if you test it with 0.0. But that should be handled by an 
epsilon for the eqZero call.

In your diff for the sign method your javadoc states:
{noformat}
* The returned value is
* <ul>
*  <li>{@code 0} if the arguments are considered equal,</li>
*  <li>{@code -1} if {@code a < b},</li>
*  <li>{@code +1} if {@code a > b} or if either value is NaN.</li>
* </ul>{noformat}
This is copied from compare. It should be:
{noformat}
* The returned value is
* <ul>
*  <li>{@code 0} if the arguments is considered equal to zero,</li>
*  <li>{@code -1} if {@code a < 0},</li>
*  <li>{@code +1} if {@code a > 0} or if either value is NaN.</li>
* </ul>{noformat}
Thinking about the result for compare, it is documented to return +1 when 
either argument is NaN. If this class is ever used for sorting (as part of a 
comparison of objects with double values) then this will result in an unstable 
sort as this violates the expected behaviour:
{noformat}
if compare(a, NaN)  == 1 then compare(NaN, a) == -1
{noformat}
Double.compare will place NaN after any non-Nan value, or any non-NaN value 
before a NaN. It returns 0 for two NaN inputs.
{noformat}
compare(a, NaN)   == -1
compare(NaN, a)   ==  1
compare(NaN, NaN) ==  0
{noformat}
I think that NaN requires some special handling. For example assuming compare 
returns 1 for NaN on either input you have:
{noformat}
eq(a, NaN)    == false 
eqZero(NaN)   == false 
lt(a, NaN)    == false
lt(NaN, a)    == false 
lte(a, NaN)   == false
lte(NaN, a)   == false 
gt(a, NaN)    == true 
gt(NaN, a)    == true
gte(a, NaN)   == true 
gte(NaN, a)   == true
sign(NaN)     == 1{noformat}
This issue is also present in the Precision class which will return +1 for the 
compare methods when NaN is one of the arguments. All the Precision methods for 
equality state that nothing is equal to NaN and there are separate methods for 
equalsIncludingNan. But the compare method does not specially handle it and so 
cannot be used for sorting/ordering.

If you have an object that implements equals and compare using Precision.equals 
and Precision.compareTo then it cannot be used in a sort as comparisons with 
NaN always return 1. If you use Precision.equalsIncludingNan then the 
comparator will fail its contract as two equal objects (NaN, NaN) will not have 
zero returned from compare(NaN, NaN).

So currently the comparisons break down when NaN is input. Is this the 
behaviour we want? If so it should be documented to not use these methods in 
comparators for sorting.

Note you can test this using:

{code:java}
@Test
void testUnstableSort() {
    Double[] array = {1.0, 2.0, 3.0, Double.NaN, Double.NaN};
    for (int i = 0; i < 10; i++) {
        Collections.shuffle(Arrays.asList(array));
        Arrays.sort(array, (a, b) -> Precision.compareTo(a, b, 1e-10));
        // CHECKSTYLE stop all
        System.out.println(Arrays.toString(array));
    }
}
{code}

Outputs some rubbish:

{noformat}
[NaN, 1.0, 2.0, 3.0, NaN]
[2.0, NaN, 1.0, NaN, 3.0]
[1.0, 2.0, 3.0, NaN, NaN]
[3.0, NaN, NaN, 1.0, 2.0]
[3.0, NaN, 1.0, 2.0, NaN]
[2.0, NaN, NaN, 1.0, 3.0]
[1.0, NaN, NaN, 2.0, 3.0]
[3.0, NaN, 1.0, NaN, 2.0]
[1.0, NaN, NaN, 2.0, 3.0]
[3.0, NaN, 1.0, 2.0, NaN]
{noformat}
 
Switching to Double.compare and it works.
 

> Move utilities from "Commons Geometry"
> --------------------------------------
>
>                 Key: NUMBERS-77
>                 URL: https://issues.apache.org/jira/browse/NUMBERS-77
>             Project: Commons Numbers
>          Issue Type: Task
>            Reporter: Gilles Sadowski
>            Priority: Major
>             Fix For: 1.1
>
>         Attachments: NUMBERS-77.diff
>
>          Time Spent: 1h 10m
>  Remaining Estimate: 0h
>
> "Commons Geometry" defines utilities that would be a better fit in this 
> component.
> Duplication of general-purpose codes should be avoided, in order to benefit 
> from consolidated usage (bug reporting, performance enhancements, ...).



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to