Skip to main content

Double.doubleToLongBits performance

9 replies [Last post]
atripp
Offline
Joined: 2003-07-15
Points: 0

The conversion of a double to a String seems slow to me. When I run this:

class Tmp {
public static void main(String[] args) {
double d1 = 12345.6789;
double d2 = 2345.6789;
double d3 = 345.6789;
double d4 = 45.6789;
for (int i=0; i<1000000; i++) {
String s = "d1=" + d1 + " d2=" +
d2+ " d2=" + " d2=" + d3 + " d4=" + d4;
}
}
}

It takes about 30 seconds real time on my 3Ghz Intel Windows XP box. When I run this with "hprof=cpu=samples,interval=20", I find that about 90% of the CPU time is spent in Double.doubleToLongBits(). Here's the stack:
java.lang.Double.doubleToLongBits(Double.java:Unknown line) sun.misc.FloatingDecimal.(FloatingDecimal.java:390) java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:681) java.lang.StringBuilder.append(StringBuilder.java:240)

This seems rather slow to me. If I go ahead and write the String s out with System.out.println(), still about half the time is spent in doubleToLongBits(), and the other half is actually doing I/O.

The native code in Double.c is doing nothing more than creating a union, storing a double, and then retrieving it as a long:
JNIEXPORT jlong JNICALL
Java_java_lang_Double_doubleToRawLongBits(JNIEnv *env, jclass unused, jdouble v)
{
union {
jlong l;
double d;
} u;
jdouble_to_jlong_bits(&v);
u.d = (double)v;
return u.l;
}

This makes me wonder if there is some "JNI overhead" here, and it might actually be faster to replace this trivial native code with Java code that converts "double bits" to "long bits".

Does that make any sense? Is there any other way to speed up converting floating point to String? Or is it just unreasonable to expect that I could do 4 million such conversions in less than 30 seconds?

Andy

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
rossk
Offline
Joined: 2006-02-02
Points: 0

Bug_id 4808791 intrinsified float/double to long bits
and was implemented in 5.0

On an Operton 2.4Ghz and using 6.0 -server I got

The append took 112 milliseconds
The format append took 111 milliseconds
The StringBuffer took 90 milliseconds
The DecimalFormat took 136 milliseconds

Message was edited by: rossk

Message was edited by: rossk

realityfaker
Offline
Joined: 2006-07-21
Points: 0

Cool!!! Is there any place on the WEB where i could look on list of inrinsics that are supported in 1.6 and 1.5 VMs?

Message was edited by: realityfaker

linuxhippy
Offline
Joined: 2004-01-07
Points: 0
atripp
Offline
Joined: 2003-07-15
Points: 0

Thanks, Hippy. Yes, that article helps. I wonder if the JCP would consider replacing the current implementation with the one mentioned in that article.

linuxhippy
Offline
Joined: 2004-01-07
Points: 0

Hi again,

I posted a link to your thread in another forum where quite many JVm developers post, and they replied:
> All of the floating point to integer conversions and
> vice versa are intrinsified by the Java HotSpot VM's
> compilers, so that native code and any associated
> overhead is not used.

So it seems conversation is that expensive, no way arround.
If they even instrified it (native code inlined by the JVM) to get rid of JNI I am quite sure its tuned as much as corectness alows.

lg Clemens

atripp
Offline
Joined: 2003-07-15
Points: 0

Clemens,
What was the other forum?

It makes sense to me that JNI is not the culprit, but what I don't understand is how so much time could be spent
in this trivial method:

JNIEXPORT jlong JNICALL
Java_java_lang_Double_doubleToRawLongBits(JNIEnv *env, jclass unused, jdouble v)
{
union {
jlong l;
double d;
} u;
jdouble_to_jlong_bits(&v);
u.d = (double)v;
return u.l;
}

I'm going to try the algorithm from Shirazi at the link you mentioned. Seems like it's faster, and no more "incorrect" than Sun's algorithm.

atripp
Offline
Joined: 2003-07-15
Points: 0

I compared Shirazi's algorithm to Sun's JDK1.5, and found them to have the same performance. On my P4 3Ghz Windows XP box, with JDK1.5.0_03 and the client VM, I got:

The append took 203 milliseconds
The format append took 204 milliseconds
The StringBuffer took 219 milliseconds
The DecimalFormat took 406 milliseconds

with -server, I got:

The append took 172 milliseconds
The format append took 141 milliseconds
The StringBuffer took 171 milliseconds
The DecimalFormat took 360 milliseconds

These numbers are from the DoubleToString class downloaded from the bottom right of http://www.onjava.com/pub/a/onjava/2000/12/15/formatting_doubles.html?pa....
The code runs through twice, and these numbers are from the second run, after the JIT has done its thing.

The "append" and "StringBuffer" numbers are virtually identical.

Going back and trying the server VM, my time is reduced quite a bit. This is all in the context of converting COBOL to Java code, and I didn't want the Java code to be any slower than the original COBOL. With the -server option, the Java is now just as fast as the COBOL that it came from.

linuxhippy
Offline
Joined: 2004-01-07
Points: 0

just to be curious, could you eventuelly re-run your tests with Mustag (java6.0 beta builds). It would just interrest me how it would perform ;)

linuxhippy
Offline
Joined: 2004-01-07
Points: 0

yes, its quite likely that you're hitting JNI overhead which is 100s of cycles, especially on a P4 (which executes complex code very poorly, Athlon64 or Core2 are way better).

What you could do is trying a SoftFloat implementation for j2me and using the server ompiler.

lg Clemene