2

Just to put my question in context: I have a class that sorts a list in its constructor, based on some calculated score per element. Now I want to extend my code to a version of the class that does not sort the list. The easiest (but obviously not clean, I'm fully aware, but time is pressing and I don't have time to refactor my code at the moment) solution would be to just use a score calculator that assigns the same score to every element.

Which double value should I pick? I was personally thinking +Infinity or -Infinity since I assume these have a special representation, meaning they can be compared fast. Is this a correct assumption? I do not know enough about the low level implementation of java to figure out if I am correct.

  • One of those, or zero if it works for you, or maybe NaN. – user207421 Jul 03 '15 at 10:25
  • @EJP could you elaborate? Is it just because they are constants? I assume the Double.compareTo function looks bit by bit, so maybe every value is acceptable. I would like to know a reasoning though. – Aäron Verachtert Jul 03 '15 at 10:30
  • Yes, it is because they have fixed representations and don't require prescaling. – user207421 Jul 03 '15 at 10:31
  • I just ran a test program with one million comparisons of constant or random double values. For all cases, I could not measure noteable runtimes (< 10ms). The Infinity comparisons were the fastest (no measurable runtime at all). – Robin Krahl Jul 03 '15 at 10:51

2 Answers2

1

No sure how this would fit in but have you considered writing your own?

It just seems a little concerning that you are looking for an object with specific performance characteristics that are unlikely to consistently appear in a general implementation. Even if you find a perfect candidate by experiment or even from source code you could not guarantee the contract.

static class ConstDouble extends Number implements Comparable<Number> {

    private final Double d;
    private final int intValue;
    private final long longValue;
    private final float floatValue;

    public ConstDouble(Double d) {
        this.d = d;
        this.intValue = d.intValue();
        this.longValue = d.longValue();
        this.floatValue = d.floatValue();
    }

    public ConstDouble(long i) {
        this((double) i);
    }

    // Implement Number
    @Override
    public int intValue() {
        return intValue;
    }

    @Override
    public long longValue() {
        return longValue;
    }

    @Override
    public float floatValue() {
        return floatValue;
    }

    @Override
    public double doubleValue() {
        return d;
    }

    // Implement Comparable<Number> fast.
    @Override
    public int compareTo(Number o) {
        // Core requirement - comparing with myself will always be fastest.
        if (o == this) {
            return 0;
        }
        return Double.compare(d, o.doubleValue());
    }

}
// Special constant to use appropriately.
public static final ConstDouble ZERO = new ConstDouble(0);

public void test() {
    // Will use ordinary compare.
    int d1 = new ConstDouble(0).compareTo(new Double(0));
    // Will use fast compare.
    int d2 = ZERO.compareTo(new Double(0));
    // Guaranteed to return 0 in the shortest time.
    int d3 = ZERO.compareTo(ZERO);
}

Obviously you would need to use Comparable<Number> rather than Double in your collections but that may not be a bad thing. You could probably craft a mechanism to ensure that the fast-track compare is always used in preference (depends on your usage).

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • What would be the advantage of this class in contrast to `Double`? – Robin Krahl Jul 03 '15 at 11:02
  • @RobinKrahl - You can **guarantee** not only that comparisons of the constant ones (such as the `ZERO` one in my sample) detect equality in minimum time but they will continue to do so through changes to the JVM. – OldCurmudgeon Jul 03 '15 at 12:27
  • @RobinKrahl - Further tinkering suggests using `Comparable` - may be better. Other alternative to `Number.compareTo` [here](http://stackoverflow.com/questions/480632/why-doesnt-java-lang-number-implement-comparable). – OldCurmudgeon Jul 03 '15 at 12:43
1

In general avoid 0.0, -0.0 and NaN. Any other number would be fine. You may look into Double.compare implementation to see that they are handled specially:

if (d1 < d2)
    return -1;           // Neither val is NaN, thisVal is smaller
if (d1 > d2)
    return 1;            // Neither val is NaN, thisVal is larger

// Cannot use doubleToRawLongBits because of possibility of NaNs.
long thisBits    = Double.doubleToLongBits(d1);
long anotherBits = Double.doubleToLongBits(d2);

return (thisBits == anotherBits ?  0 : // Values are equal
        (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
         1));                          // (0.0, -0.0) or (NaN, !NaN)

However that depends on how your sorting comparator is implemented. If you don't use Double.compare, then probably it doesn't matter.

Note that except these special cases with 0.0/-0.0/NaN double numbers comparison is wired inside the CPU and really fast, thus you are unlikely to get any significant comparison overhead compared to the other code you already have.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334