0

Here is a simple code snippet of java

float start = System.nanoTime();
for(int i=0;i<1000000000;i = i+1){}
float end = System.nanoTime();
System.out.println("Time taken : " + (end-start)/1000000000);

This gives output 0.004194304 seconds where as :

for(double i=0;i<1000000000;i = i+1){}

this code where I just changed the type of i from int to double takes 3.8970327 seconds. My question is how to improve this really bad performance of double in java

2rd_7
  • 462
  • 1
  • 3
  • 15
  • 2
    Yes, adding 1 to an `int` is a lot simpler than adding 1 to a `double`. Is this a bottleneck in your *real* code? – Jon Skeet May 30 '16 at 07:21
  • 1
    if you want a numeric range bigger than `int` then use `long` instead of `double` type. –  May 30 '16 at 07:22
  • 1
    I suspect that in the `int` case the loop has been optimized away. Anyway - JAFMB - "just another flawed micro-benchmark". – Stephen C May 30 '16 at 07:26
  • Mandatory link: http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java – reto May 30 '16 at 08:01

2 Answers2

1

First of all, I think your int benchmark is giving a specious answer. The number simply fails the common sense test!!

Incrementing from 1 to 1,000,000,000 should perform 1 billion increments, 1 billion stores, 1 billion tests, 1 billion branches. All of that is supposedly happening in ~0.004 seconds. That implies a 4 billion instructions in 0.004 seconds, or 1 trillion instructions in 1 second ... or a clock rate of some multiple of 1.0E12. But the fastest intel processors around have clock rate less than 10 GHz ... or 1.0E10.

In fact, what I think has happened is that the JIT compiler has figured out that your loop is doing no useful work, and has optimized it away.

For some reason, the JIT compiler has not figured out that the version with the double is also not doing useful work either.

But either way, 1 billion floating point operations in 3 seconds using a single processor is pretty good performance ...

My question is how to improve this really bad performance of double in java

  1. It is not really bad performance.

  2. It is (approximately) real performance ... and the int performance you are seeing is bogus.

  3. You can't improve on it.


Actually, you are kind of lucky that the double loop terminates at all. Consider this version:

 for (double i = 0; i < Integer.MAX_VALUE; i = i + 1){}

 for (float i = 0; i < Integer.MAX_VALUE; i = i + 1){}

The float version should be faster. Right?

Wrong!

The problem is that a float only has 24 bits (7.22 decimal digits) of precision. So, somewhere between 1.0E7 and 1.0E8, you will get to a point where i + 1 evaluates to i ... due to rounding. That leads to an infinite loop.

When you think about it, it is this kind of thing that could cause the JIT compiler to not optimize away a floating point loop.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Yeah!!.....You are right. The compiler optimized the code by itself. I tried doing some O(1) stuff in the loop and then it needed an execution time of 1.6 seconds. But I do not get how `i+1` evaluates to `i` if `float` is used. I am sorry if this question is trivial but I don't get it. As far as I know the number should get truncated at the last or should wrap to the beginning. – 2rd_7 May 30 '16 at 09:56
  • Re: the float example, try it and see!! Remember that `i` is a `float` not an `int`, and that *therefore* `i + 1` is a floating point operation. Floating point operations do not wrap around or truncate. Instead, the notional result of the operation is *rounded* to the nearest value that is representable as an IEE 32 bit floating bit value. – Stephen C May 30 '16 at 12:07
  • Then you need to understand that as IEE floating point numbers get larger, the "gaps" between successive values get larger. At some point, the gap will be > 2.0, and you will find there is a case where `i + 1.0` gets rounded to `i` ... as being the nearest *representable* floating point number. – Stephen C May 30 '16 at 13:19
-1

It's normal because a int take 4 bytes in memory while double takes 8 bytes (it has decimals). Maybe you can prove BigDecimal.

Lucke
  • 316
  • 6
  • 18