Recent Java enhancements for numeric calculations

September 13, 2021 - Reading time: 2 minutes

In the past, slow evaluation of mathematical functions and large memory footprint were the most significant drawbacks of Java compared to C++/C for numeric computations and scientific data analysis. However, recent enhancements in the Java Virtual Machine (JVM) enabled faster and better numerical computing due to several enhancements in evaluating trigonometric functions.

In this article we will use the DataMelt (https://datamelt.org) for our benchmarks. Let us consider the following algorithm implemented in the Groovy dynamically-typed language shown below. It uses a large loop, repeatedly calling the sin() and cos() functions. Save these lines in a file with the extension "goovy" and run it in DataMelt:


import java.lang.Math
long then = System.nanoTime()
double x=0
for (int i = 0; i < 1e8; i++)
x=x+Math.sin(i)/Math.cos(i)
itime = ((System.nanoTime() - then)/1e9)
println "Time: " + itime+" (sec) result="+x

The execution of this Groovy code is typically a 10-20% faster than for the equivalent code implemented in Python:


import math,time
then = time.time()
x=0
for i in xrange(int(1e8)):
x=x+math.sin(i)/math.cos(i)
itime = time.time() - then
print("Time:",itime," (sec) result=",x)

Note that CPython2 (version 2.7.2) is a 20% faster than CPython3 (version 3.4.2), but both CPython interpreters are slower for this example than Groovy.

The same algorithm re-implemented in Java:


import java.lang.Math;
public class Example {
public static void main(String[] args) {
long then = System.nanoTime();
double x=0;
for (int i = 0; i < (int)1e8; i++)
x=x+Math.sin(i)/Math.cos(i);
double itime = ((System.nanoTime() - then)/1e9);
System.out.println("Time for calculations (sec): " + itime+"\n");
System.out.println("Pi = " + x +"\n");
}
}

and processed using DataMelt with OpenJDK13 further increases the execution speed by a factor 2 compared to the Groovy dynamic language.

Similar benchmarks of the Java code have been carried out by repeating the calculation using Java SE 8 ("JDK1.8") released in March 2014. The computation was about a factor 8 slower than for the OpenJDK13. This was due to less optimized code for evaluation of trigonometric functions in JDK1.8 (and earlier versions). This confirms significant improvements for numeric computations in the recent JVM compared to the previous releases.

The question of code profiling using different implementations is a complex problem, and we do not plan to explore all possible scenarios in this article. The main conclusion we want to draw in this section is that the processing speed of the code that implements mathematical functions for numeric calculations is substantially better for Groovy than for CPython2 (CPython3). The observed performance improvements in dynamically-typed languages implemented in Java are due to the recent enhancements in the modern JVMs, leading to a large factor in the speed of evaluations
of mathematical functions.

Sergei Chekanov

Category: