In my last post I discussed three methods for primality test suitable for ICSE/ISC students. The first method was quite slow, the second and third methods were considerably faster. In this post we will see how we can measure or visualize the performance of an algorithm. We can use profiling tools which comes bundled with major IDEs like Eclipse or Netbeans, unfortunately BlueJ, the recommended editor by CISCE doesn’t come with a inbuilt profiler. Instead of downloading and learning a new tool we will see how to time a method in Java. The timing methods in java which we will employing in this post are not very accurate and depending on the hardware and the platform used but since we are interested in overall trends this inaccuracy won’t be an issue.

Java has a function System.nanoTime() which* returns the current value of the running Java Virtual Machine’s high-resolution time source, in nanoseconds*. We can use System.nanoTime() to measure the time elapsed in executing a certain code e.g.

long startTime = System.nanoTime(); // ... the code being measured ... long estimatedTime = System.nanoTime() - startTime;

The above will return the time elapsed in nano seconds. Students are advised to visit the documentation of System.nanoTime() for details.

In order to apply the above logic in the isPrime( ) implementation of the previous post we will rename the three isPrime() implementation to isPrime1(), isPrime2 and isPrime3() respectively. We will also add some code to call and time the above functions. The final code will be as follows:

class Prime{ public static boolean isPrime1(int number){ for(int i=1; i<=number; i++){ if(number%i==0){ factorCount++; } } if(factorCount==2) return true; else return false; } public static boolean isPrime2(int number){ if(number<2) return false; else if(number==2) return true; else if(number%2==0) return false; else{ for(int i=3; i<number;i+=2){ if(number%i==0){ return false; } } } return true; } public static boolean isPrime3(int number){ if(number<2) return false; else if(number==2) return true; else if(number%2==0) return false; else{ int limit = (int)Math.sqrt(number); for(int i=3; i<=limit;i+=2){ if(number%i==0){ return false; } } } return true; } public static void benchmark(){ long startTime,estimatedTime; boolean primeStatus=false; int testcase[]={1,5,10,50,100,200,500,1000,5000, 10000, 50000, 60000,70000,80000,90000, 100000}; System.out.println("n\tisPrime1\tisPrime2\tisPrime3"); for(int i=0; i<testcase.length; i++){ System.out.print(testcase[i]+"\t"); startTime= System.nanoTime(); primeStatus=isPrime1(testcase[i]); estimatedTime = System.nanoTime()- startTime; System.out.print(estimatedTime+"\t\t"); startTime= System.nanoTime(); primeStatus=isPrime2(testcase[i]); estimatedTime = System.nanoTime()- startTime; System.out.print(estimatedTime+"\t\t"); startTime= System.nanoTime(); primeStatus=isPrime3(testcase[i]); estimatedTime = System.nanoTime()- startTime; System.out.println(estimatedTime); } } public static void main(String args[]){ benchmark(); } }

When the above code is executed the output will vary due to differences in hardware and software. On my system the output is as follows:

n | isPrime1 | isPrime2 | isPrime3 |

1 | 2960 | 3058 | 2777 |

5 | 1108 | 940 | 49163 |

10 | 1267 | 786 | 740 |

50 | 1929 | 720 | 731 |

100 | 2946 | 770 | 735 |

200 | 4285 | 781 | 715 |

500 | 11291 | 764 | 786 |

1001 | 21007 | 1050 | 1455 |

5001 | 128459 | 865 | 1165 |

10001 | 1495611 | 2144 | 2540 |

50001 | 317681 | 1002 | 1613 |

60001 | 360096 | 1266 | 1651 |

70001 | 391876 | 1581356 | 4552 |

80001 | 346825 | 14924 | 1318 |

90001 | 407214 | 272037 | 4576 |

100001 | 460347 | 1169 | 2933 |

All time intervals are in nano seconds. The difference between the runtime of isPrime1() and isPrime2() is clearly evident but one may be surprised that isPrime3() is not the best for all the given set of values! The reason for this discrepancy is that the Math.sqrt() function of Java returns a double value and is computationally intensive. The problem can be removed by using a custom function for computing the square root which optimized for integers. I am not going to discuss them over here because they lie outside the scope of ICSE/ISC syllabus, those interested can visit http://atoms.alife.co.uk/sqrt/ for one such implementation.

Pingback: Prime time | VinaySingh.info

Mohit NandaThanks for benchmarking it.

So, we do find a case here, that what seems intuitively more efficient was actually not always, which is a very common scenario that we as performance consultants deal with every day. 🙂

Also, there is a large anomaly for n=5 in isPrime3(). Is the result repeatable and consistent? Is the cause known?

Vinay SinghPost authorYou are right Mohit and this reminds me of the quote “In theory there is no difference between theory and practice. In practice there is”! 🙂

The anomaly for n=5 in isPrime3() is repeatable and consistent. I am exploring it but as of now I am not sure of the cause. 🙁

Pingback: Finding sine of an angle in Java without using the Math class | VinaySingh.info