The most efficient code is the code you never write. Don't do for yourself what experts have already done,
Elliotte Rusty Harold reviews new mathematical functions in java.lang.Math in Java's new math.
The latest two version of the JDK each added 10 new methods to java.lang.Math. One reason those methods are important learn about is because they are almost certain to provide more efficient, and more accurate, implementations than what most developers would write themselves for certain calculations. In additions, many methods in java.lang.Math take advantage of native code that, in turn, exploits hardware acceleration on modern CPUs.
In the article, Harold notes many instances where a naive approach could lead to incorrect calculations, starting with such basic notions as the size of a number:
The Platonic ideal of the number is infinitely precise, while the Java representation is limited to a fixed number of bits. This is important when you deal with very large and very small numbers. For example, the number 2,000,000,001 (two billion and one) can be represented exactly as an int, but not as a float. The closest you can get in a float is 2.0E9 — that is, two billion.
Proper calculations of sine and other functions that are both accurate and fast require very careful algorithms designed to avoid accidentally turning small errors into large ones. Often these algorithms are embedded in hardware for even faster performance.
For example, almost every X86 chip shipped in the last 10 years has hardware implementations of sine and cosine that the X86 VM can just call, rather than calculating them far more slowly based on more primitive operations. HotSpot takes advantage of these instructions to speed up trigonometry operations dramatically.
In the rest of his article, Harold reviews some of the most useful new java.lang.Math methods, such as Math.hypot that calculates the Pythagorean equation:
Java 5 added a Math.hypot function to perform exactly this calculation, and it's a good example of why a library is helpful. The naive approach would look something like this:
The actual code [as implemented in java.lang.Math] is somewhat more complex... The first thing you'll note is that this is written in native C code for maximum performance. The second thing you should note is that it is going to great lengths to try to minimize any possible errors in this calculation. In fact, different algorithms are being chosen depending on the relative sizes of x and y.
The latest version of java.lang.Math also corrects naming issues with the log method:
Logs base 10 tend to appear in engineering applications. Logs base e (natural logarithms) appear in the calculation of compound interest, and numerous scientific and mathematical applications. Logs base 2 tend to show up in algorithm analysis.
The Math class has had a natural logarithm function since Java 1.0. That is, given an argument x, the natural logarithm returns the power to which e must be raised to give the value x. Sadly, the Java language's (and C's and Fortran's and Basic's) natural logarithm function is misnamed as log(). In every math textbook I've ever read, log is a base-10 logarithm, while ln is a base e logarithm and lg is a base-2 logarithm. It's too late to fix this now, but Java 5 did add a log10() function that takes the logarithm base 10 instead of base e... Math.log10() has the usual caveats of logarithm functions: taking the log of 0 or any negative number returns NaN.
Harold also explains the Math.cbrt(), the hyperbolic trigonometric functions Math.cosh(), Math.sinh(), and Math.tanh(), as well as Math.signum.
What do you think of the latest math-related functions in Java?
If the performance of a Math method is deemed important then the JVM implementer can transparently replace the C implementation with an intrinsic form. This already happens with methods like Math.sin()
> The latest version of <code>java.lang.Math</code> also > corrects naming issues with the <code>log</code> > method:</p> > > Sadly, the Java language's (and C's and > Fortran's and Basic's) natural logarithm function is > misnamed as log(). In every math textbook I've ever read, > log is a base-10 logarithm, while ln is a base e logarithm > and lg is a base-2 logarithm. It's too late to fix this > now, but Java 5 did add a log10() function that takes the > logarithm base 10 instead of base e... Math.log10() has > the usual caveats of logarithm functions: taking the log > of 0 or any negative number returns NaN. </p> >
Actually calling the logarithm base e "log" is not misnamed. There exist different naming conventions.
See e.g. the wikipedia entry for logarithm or http://mathworld.wolfram.com/Logarithm.html "Note that while logarithm base 10 is denoted log(x) in this work, on calculators, and in elementary algebra and calculus textbooks, mathematicians and advanced mathematics texts uniformly use the notation log(x) to mean ln(x), and therefore use log_(10)x to mean the common logarithm. Extreme care is therefore needed when consulting the literature."