Does this mean that Java Math.floor is extremely slow?

I don’t have much Java.

I am writing some optimized math code and I was shocked by the results of my profilers. My code collects the values, interleaves the data, and then selects the values ​​based on this. Java is slower than my C ++ and MATLAB implementations.

I am using javac 1.7.0_05 I am using Sun / Oracle JDK 1.7.05

There is a floor function that performs the corresponding task in code. java math.floor profile results

  • Does anyone know of a paradigmatic way to fix this?
  • I noticed that my floor() function is defined using StrictMath . Is there something like -ffast-math for Java? I expect that there should be a way to change the gender function to something more reasonably computational without writing my own.

     public static double floor(double a) { return StrictMath.floor(a); // default impl. delegates to StrictMath } 

Edit

So, several people suggested I try to make a throw. I tried this, and there were no changes in the walls.

 private static int flur(float dF) { return (int) dF; } 

413742 cast floor function

394675 Math.floor

These tests were performed without a profiler. An effort was made to use the profiler, but the runtime was radically changed (15 minutes, so I left).

+16
java performance profiling floor
Aug 21 '12 at 6:18
source share
5 answers

Here you can test your hypothesis that the code really spends 99% of its time in floor . Suppose you have versions of Java and C ++ algorithms that are correct in terms of the results they produce. For the argument, suppose two versions call equivalent floor functions the same number of times. So the time function

 t(input) = nosFloorCalls(input) * floorTime + otherTime(input) 

where floorTime is the time spent calling floor on the platform.

Now, if your hypothesis is true, and floorTime significantly more expensive in Java (to the extent that it takes about 99% of the execution time), then you expect that the version of the Java application will work at a higher rate (50 times or more) more slowly, than the C ++ version. If you do not see this, your hypothesis is likely to be false.




If the hypothesis is false, here are two alternative explanations for the profiling results.

  • This is an anomaly of measurement; those. the profiler somehow made a mistake. Try using a different profiler.

  • There is an error in the Java version of your code that causes floor to be called many times more than in the C ++ version of the code.

+6
Aug 21 '12 at 7:14
source share

You might want to try FastMath .

Here is a post on Math performance in Java vs. Javascript . There are some good tips on why math is slow by default. They discuss other operations than floor , but I think their results can be summarized. It was interesting to me.

EDIT

According to this error record, the floor implemented pure Java code in 7 (b79), 6u21 (b01), which leads to better performance. The floor code in JDK 6 is still a bit longer than in FastMath , but cannot be held responsible such a perfect. degradation. Which JDK are you using? Could you try with a newer version?

+8
Aug 21 2018-12-12T00:
source share

Math.floor() runs flawlessly quickly on my machine in about 7 nanoseconds in one call in a narrow loop. (Windows 7, Eclipse, Oracle JDK 7). I would expect it to be very fast in almost all circumstances and would be very surprised if this turns out to be a bottleneck.

Some ideas:

  • I would suggest re-running some tests without a profiler working . It sometimes happens that profilers create false overhead when they process a binary file - especially for small functions like Math.floor() that can be built in.
  • Try a few different JVMs, you may have encountered an unclear error
  • Try the FastMath class in the excellent Apache Commons Math library, which includes a new gender implementation. I would be very surprised if it were faster, but you never know.
  • Make sure that you are not using virtualization technology or similar, which may interfere with the Java ability to call native code (which is used in several functions of java.lang.Math , including Math.floor() )
+5
Aug 21 2018-12-12T00:
source share

First of all: your profiler shows that your expenses are 99% of the CPU time in the gender function. This does not mean that the floor is slow. If you do nothing but gender (), this is absolutely great. However, since other languages ​​seem to use gender more efficiently, your guess may be correct.

I know from school that a naive gender implementation (which works only for positive numbers and one for negative numbers) can be done by casting integer / long. This is a language agnostic and some general knowledge from CS courses.

Here are a few micro benches. It works on my machine and supports what I learned at school;)

 rataman@RWW009 ~/Desktop $ javac Cast.java && java Cast 10000000 Rounds of Casts took 16 ms rataman@RWW009 ~/Desktop $ javac Floor.java && java Floor 10000000 Rounds of Floor took 140 ms 
#
 public class Cast/Floor { private static final int ROUNDS = 10000000; public static void main(String[] args) { double[] vals = new double[ROUNDS]; double[] res = new double[ROUNDS]; // awesome testdata for(int i = 0; i < ROUNDS; i++) { vals[i] = Math.random() * 10.0; } // warmup for(int i = 0; i < ROUNDS; i++) { res[i] = floor(vals[i]); } long start = System.currentTimeMillis(); for(int i = 0; i < ROUNDS; i++) { res[i] = floor(vals[i]); } System.out.println(ROUNDS + " Rounds of Casts took " + (System.currentTimeMillis() - start) +" ms"); } private static double floor(double arg) { // Floor.java return Math.floor(arg); // or Cast.java return (int)arg; } 

}

+4
Aug 21 '12 at 6:28
source share

It is worth noting that monitoring the method requires some overhead, and in the case of VisualVM this is a rather high level. If you have a method that is called frequently, but it may seem very small, it uses a lot of CPU. for example I saw Integer.hashCode () as a big striker once .;)

On my machine, the floor takes less than 5.6 ns, but the cast takes 2.3 ns. You can try it on your car.




If you don’t need to handle corner cases, simple casting is faster.

 // Rounds to zero, instead of Negative infinity. public static double floor(double a) { return (long) a; } 



 public static void main(String... args) { int size = 100000; double[] a = new double[size]; double[] b = new double[size]; double[] c = new double[size]; for (int i = 0; i < a.length; i++) a[i] = Math.random() * 1e6; for (int i = 0; i < 5; i++) { timeCast(a, b); timeFloor(a, c); for (int j = 0; j < size; j++) if (b[i] != c[i]) System.err.println(a[i] + ": " + b[i] + " " + c[i]); } } public static double floor(double a) { return a < 0 ? -(long) -a : (long) a; } private static void timeCast(double[] from, double[] to) { long start = System.nanoTime(); for (int i = 0; i < from.length; i++) to[i] = floor(from[i]); long time = System.nanoTime() - start; System.out.printf("Cast took an average of %.1f ns%n", (double) time / from.length); } private static void timeFloor(double[] from, double[] to) { long start = System.nanoTime(); for (int i = 0; i < from.length; i++) to[i] = Math.floor(from[i]); long time = System.nanoTime() - start; System.out.printf("Math.floor took an average of %.1f ns%n", (double) time / from.length); } 

prints

 Cast took an average of 62.1 ns Math.floor took an average of 123.6 ns Cast took an average of 61.9 ns Math.floor took an average of 6.3 ns Cast took an average of 47.2 ns Math.floor took an average of 6.5 ns Cast took an average of 2.3 ns Math.floor took an average of 5.6 ns Cast took an average of 2.3 ns Math.floor took an average of 5.6 ns 
+4
Aug 21 '12 at 7:23
source share



All Articles