Jeff,

Your"ceil" and "floor" seems correct for me.
I benchmarked your code by attached benchmark program.
It is faster on some test patterns and with some Jvm options and it is slower on some others.

Joe,

I'm curious how performance decisions are made in Jdk development process.
Are there performance benchmarks in Jdk source tree ? Which platforms are
considered and with which weight ?

 -Dima

The benchmarks results on my OpenSolaris opteron computer (jdk7-b79):

pattern1 is  {+0.0, +0.5, +1.0, +1.5, +2.0, +2.5, +3.0, +3.5, +4.0}.
pattern2 is {+0.0, -0.0, +1.5, -1.5, 1000.0, -1000.0, (1L << 40), -(1L << 40), Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}.


*** pattern1  -d32 -client
empty took 2,52 nsec Math.ceil took 24,23 nsec Math.floor took 23,56 nsec StrictMath.ceil took 24,59 nsec StrictMath.floor took 24,08 nsec FloorCeil.ceil took 13,91 nsec FloorCeil.floor took 11,31 nsec
*** pattern1  -d32 -server
empty took 1,67 nsec Math.ceil took 10,29 nsec Math.floor took 10,44 nsec StrictMath.ceil took 10,27 nsec StrictMath.floor took 10,44 nsec FloorCeil.ceil took 9,01 nsec FloorCeil.floor took 5,28 nsec
*** pattern1  -d64 -client
empty took 1,69 nsec Math.ceil took 6,92 nsec Math.floor took 6,18 nsec StrictMath.ceil took 6,90 nsec StrictMath.floor took 6,18 nsec FloorCeil.ceil took 8,31 nsec FloorCeil.floor took 5,35 nsec
*** pattern1  -d64 -server
empty took 1,67 nsec Math.ceil took 6,73 nsec Math.floor took 6,07 nsec StrictMath.ceil took 6,73 nsec StrictMath.floor took 6,07 nsec FloorCeil.ceil took 9,00 nsec FloorCeil.floor took 5,25 nsec
*** pattern2  -d32 -client
empty                took       2,58 nsec
Math.ceil            took      24,24 nsec
Math.floor           took      23,99 nsec
StrictMath.ceil      took      24,25 nsec
StrictMath.floor     took      24,34 nsec
FloorCeil.ceil       took      15,94 nsec
FloorCeil.floor      took      16,45 nsec

*** pattern2  -d32 -server
empty                took       1,67 nsec
Math.ceil            took      12,38 nsec
Math.floor           took      12,26 nsec
StrictMath.ceil      took      12,54 nsec
StrictMath.floor     took      12,31 nsec
FloorCeil.ceil       took       9,08 nsec
FloorCeil.floor      took       9,64 nsec

*** pattern2  -d64 -client
empty                took       1,67 nsec
Math.ceil            took       6,07 nsec
Math.floor           took       6,33 nsec
StrictMath.ceil      took       6,00 nsec
StrictMath.floor     took       6,39 nsec
FloorCeil.ceil       took       9,81 nsec
FloorCeil.floor      took       7,39 nsec

*** pattern2  -d64 -server
empty                took       1,67 nsec
Math.ceil            took       6,32 nsec
Math.floor           took       6,27 nsec
StrictMath.ceil      took       6,40 nsec
StrictMath.floor     took       6,37 nsec
FloorCeil.ceil       took       9,69 nsec
FloorCeil.floor      took       7,39 nsec

------------------------ The benchmark code
package floorceilingtests;

public class Main {

   public static void main(String[] args) {
       double[] a = new double[1000];
       int pattern = 1;
       switch (pattern) {
           case 1:
               pattern1(a);
               break;
           case 2:
               pattern2(a);
               break;
       }
       new Main().test(a);
   }

   private static void pattern1(double[] a) {
       for (int i = 0; i < a.length; i += 10) {
           a[i+0] = +0.0;
           a[i+2] = +0.5;
           a[i+3] = +1.0;
           a[i+4] = +1.5;
           a[i+5] = +2.0;
           a[i+6] = +2.5;
           a[i+7] = +3.0;
           a[i+8] = +3.5;
           a[i+9] = +4.0;
       }
   }

   private static void pattern2(double[] a) {
       for (int i = 0; i < a.length; i += 10) {
           a[i+0] = +0.0;
           a[i+1] = -0.0;
           a[i+2] = +1.5;
           a[i+3] = -1.5;
           a[i+4] = 1000.0;
           a[i+5] = -1000.0;
           a[i+6] = (1L << 40);
           a[i+7] = -(1L << 40);
           a[i+8] = Double.POSITIVE_INFINITY;
           a[i+9] = Double.NEGATIVE_INFINITY;
       }
   }

   private void test (double[] args) {
       for (int i = 0; i < 5; i++) {
           System.out.println();
           for (Benchmark b: benchmarks) {
               b.run(args, 100000);
           }
       }
   }

   private Benchmark[] benchmarks = {
       new Benchmark("empty") {
           double run(double[] args) {
               double s = 0;
               for (double d: args) {
                   s += d;
               }
               return s;
           }
       },
       new Benchmark("Math.ceil") {
           double run(double[] args) {
               double s = 0;
               for (double d: args) {
                   s += Math.ceil(d);
               }
               return s;
           }
       },
       new Benchmark("Math.floor") {
           double run(double[] args) {
               double s = 0;
               for (double d: args) {
                   s += Math.floor(d);
               }
               return s;
           }
       },
       new Benchmark("StrictMath.ceil") {
           double run(double[] args) {
               double s = 0;
               for (double d: args) {
                   s += StrictMath.ceil(d);
               }
               return s;
           }
       },
       new Benchmark("StrictMath.floor") {
           double run(double[] args) {
               double s = 0;
               for (double d: args) {
                   s += StrictMath.floor(d);
               }
               return s;
           }
       },
       new Benchmark("FloorCeil.ceil") {
           double run(double[] args) {
               double s = 0;
               for (double d: args) {
                   s += FloorCeil.ceil(d);
               }
               return s;
           }
       },
       new Benchmark("FloorCeil.floor") {
           double run(double[] args) {
               double s = 0;
               for (double d: args) {
                   s += FloorCeil.floor(d);
               }
               return s;
           }
       }
   };


   private abstract static class Benchmark {
       private final String name;

       private Benchmark(String name) {
           this.name = name;
       }

       abstract double run(double[] args);

       void run(double[] args, int repeatCount) {
           long startTime = System.nanoTime();
           double s = 0;
           for (int i = 0; i < repeatCount; i++) {
               s += run(args);
           }
           long stopTime = System.nanoTime();
System.out.printf("%-20s took %10.2f nsec %s\n", name, (stopTime - startTime)/(double)repeatCount/args.length, s > 0 ? " " : "");
       }
   }
}
------------------------




Jeff Hain wrote:
Hello.
I happen to already have developped some pure Java version of ceil(double) and floor(double). It looks faster to me. But maybe is it incorrect ? (it's tested, but I'm never sure)
Here it is :
public class FloorCeil { private static final double TWO_POW_26 = Double.longBitsToDouble(0x4190000000000000L); private static final double TWO_POW_N26 = Double.longBitsToDouble(0x3E50000000000000L); private static final double TWO_POW_52 = Double.longBitsToDouble(0x4330000000000000L);
    public static double floor(double value) {
        // Faster than to work directly on bits.
        if (Math.abs(value) <= (double)Integer.MAX_VALUE) {
            if (value > 0.0) {
                return (double)(int)value;
            } else if (value < 0.0) {
                double anteComaDigits = (double)(int)value;
                if (value != anteComaDigits) {
                    return anteComaDigits - 1.0;
                } else {
                    return anteComaDigits;
                }
} else { // value is +-0.0 (not NaN due to test against Integer.MAX_VALUE)
                return value;
            }
        } else if (Math.abs(value) < TWO_POW_52) {
            // We split the value in two:
            // high part, which is a mathematical integer,
            // and the rest, for which we can get rid of the
            // post coma digits by casting into an int.
            double highPart = ((int)(value * TWO_POW_N26)) * TWO_POW_26;
            if (value > 0.0) {
                return highPart + (double)((int)(value - highPart));
            } else {
double anteComaDigits = highPart + (double)((int)(value - highPart));
                if (value != anteComaDigits) {
                    return anteComaDigits - 1.0;
                } else {
                    return anteComaDigits;
                }
            }
        } else { // abs(value) >= 2^52, or value is NaN
            return value;
        }
    }
    public static double ceil(double value) {
        return -floor(-value);
    }
}
Jeff


Reply via email to