Code review request for 6908131 Pure Java implementations of StrictMath.floor(double) &StrictMath.ceil(double)
Dmitry Nadezhin
Dmitry.Nadezhin at Sun.COM
Thu Jan 21 06:27:05 UTC 2010
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
>
>
>
>
More information about the core-libs-dev
mailing list