How to make java code perform better in for loop? - java

When executed once, code 1 is faster than code 2. The difference is quite significant.
But, when these codes are executed inside for loop (50 million times, see code 1 inside for loop and code 2 inside for loop) code 1 has the worst performance.
Is it possible to make code 1 perform better inside for loop?
Another question: is there another way to do these calculations inside for loop with a better performance?
int [] arr1 = new int[50000000];
for (int i = 0; i < 50000000; i++) {
arr1[i] = i + 1000;
}
//code 1:
long startTime1 = System.nanoTime();
int som1 = 426;
double a1 = (double) ((((double) Math.round((double) Math.pow((double) arr1[arr1.length - 1] / (double) som1, 2)) - 1) / 50 % 1) * 50) + 1;
int a2 = (int) Math.round(a1);
long estimatedTime1 = System.nanoTime() - startTime1;
System.out.println("Code 1: " + estimatedTime1);
//code 2:
long startTime2 = System.nanoTime();
int som2 = 426;
double a3 = (double) arr1[arr1.length - 1] / (double) som2;
double a4 = (double) (Math.round(a3 * a3) - 1);
double a5 = (double) a4 / 50;
double a6 = (double) Math.floor(a5);
double a7 = (double) ((a5 - a6) * 50) + 1;
int a8 = (int) Math.round(a7);
long estimatedTime2 = System.nanoTime() - startTime2;
System.out.println("Code 2: " + estimatedTime2);
//code 1 inside for loop:
long startTime3 = System.nanoTime();
int som3 = 426;
for (int j1 = 0; j1 < arr1.length; j1++) {
double a9 = (double) ((((double) Math.round((double) Math.pow((double) arr1[j1] / (double) som1, 2)) - 1) / 50 % 1) * 50) + 1;
int a10 = (int) Math.round(a9);
}
long estimatedTime3 = System.nanoTime() - startTime3;
System.out.println("Code 1 inside for loop: " + estimatedTime3);
//code 2 inside for loop:
long startTime4 = System.nanoTime();
int som4 = 426;
for (int j2 = 0; j2 < arr1.length; j2++) {
double a11 = (double) arr1[j2] / (double) som4;
double a12 = (double) (Math.round(a11 * a11) - 1);
double a13 = (double) a12 / 50;
double a14 = (double) Math.floor(a13);
double a15 = (double) ((a13 - a14) * 50) + 1;
int a16 = (int) Math.round(a15);
}
long estimatedTime4 = System.nanoTime() - startTime4;
System.out.println("Code 2 inside for loop: " + estimatedTime4);
Edit : As explained by #Sweeper, code 1 is slower in both cases. As I am trying to improve the performance of this code inside for loop, I would like to ask if there is a faster way to do these calculations inside for loop.

Related

Java: Palindrome, not getting biggest number

I want to get the largest palindrome number of 3-digit numbers. This is my code:
for (int start = 100; start < 1000; start++) {
for (int start2 = 100; start2 < 1000; start2++) {
int temp = start * start2;
int biggest = 1;
String strTemp = temp + "";
if (strTemp.equals(new StringBuilder(strTemp).reverse().toString())) {
if (temp > biggest) {
biggest = temp;
System.out.println("Original: " + strTemp);
System.out.println("Reverse: " + new StringBuilder(strTemp).reverse().toString());
System.out.println("Siffra: " + start);
System.out.println("Siffra2: " + start2);
}
}
}
In the end, I get 995 x 583 and not 993 x 913, which is the largest one. Why? I have it so the int biggest always chooses the biggest number.
You need to move int biggest = 1; out of both for loops.
If you don't do that at every inner loop you restart the value of biggest.
int biggest = 1;
for (int start = 100; start < 1000; start++) {
for (int start2 = 100; start2 < 1000; start2++) {
int temp = start * start2;
String strTemp = temp + "";
if (strTemp.equals(new StringBuilder(strTemp).reverse().toString())) {
if (temp > biggest) {
biggest = temp;
System.out.println("Original: " + strTemp);
System.out.println("Reverse: " + new StringBuilder(strTemp).reverse().toString());
System.out.println("Siffra: " + start);
System.out.println("Siffra2: " + start2);
}
}
}
With java 8 you can rewrite this code as follow:
// Define what it means palindrome
IntPredicate isPalindrome = n -> new StringBuffer(String.valueOf(n)).reverse().toString().equals(String.valueOf(n));
OptionalInt max =
// Define a stream from 100 to 1000
IntStream.range(100, 1000)
// Map the original stream to a new stream
// Basically for each x of the first stream
// creates a new stream 100-1000 and map each element
// x of the first stream and y of the second stream
// to x * y
.flatMap(x -> IntStream.range(100, 1000).map(y -> x * y))
// Take only palyndrome of x * y
.filter(isPalindrome)
// take the max
.max();
A functional approach is more readable in most cases where you have to loop over n elements and is easier to filter and extract elements without
doing errors.
Move your declaration of biggest outside the loops:
int biggest = 1;
for (int start = 100; start < 1000; start++) {
for (int start2 = 100; start2 < 1000; start2++) {
int temp = start * start2;
String strTemp = temp + "";
if (strTemp.equals(new StringBuilder(strTemp).reverse().toString())) {
if (temp > biggest) {
biggest = temp;
System.out.println("Original: " + strTemp);
System.out.println("Reverse: " + new StringBuilder(strTemp).reverse().toString());
System.out.println("Siffra: " + start);
System.out.println("Siffra2: " + start2);
}
}
}
Output:
....
Original: 906609
Reverse: 906609
Siffra: 913
Siffra2: 993
int biggest = 1;
for (int start = 100; start < 1000; start++) {
for (int start2 = 100; start2 < 1000; start2++) {
int temp = start * start2;
in above you are initializing biggest=1 always. so you not getting proper result. Keep it outside of for loop.

adding fractions using recursion e=1+1/1!+1/2!+1/3!+

I need to write a recursive method to compute the following series:
e = 1+1/1!+1/2!+1/3!+...
This is what I have so far.
public static void main(String[] args)
{ System.out.println("enter n :");
int n =scan.nextInt();
double h = fact(n);
System.out.println(" e = ");
}
public double fact(int n)
{
if (n == 1)
return 1;
else
return ???;
}
}
So, assuming the n input you're taking is the starting denominator for the smallest fraction you'd add...
(For example, given n = 10, you want to add 1 through 1/10)
Then you need to set up your method so that when you call fact(10), it's going to return the sum of 1/10 plus the result of fact(9), or more generically, 1/n + fact(1/n-1);
So, you're looking for something like this:
public double fact(int n) {
if (n < 0) {
return 0.0;
} else if (n == 0) {
return 1.0;
} else {
return (1.0/n + fact(n-1))
}
}
Also, please note the changes to the base cases. When n < 0, we just return 0.0, because if I recall correctly, the factorial of any negative number is always 0, right?
Meanwhile, the base case should be n==0, not n == 1. Your series starts with 1 + 1/1. Note that 1 is not 1/0 or 1/nothing, it's just 1/1. We can't return 1/n when n is 0. For the series to calculate correctly, we have to add the first return the first element of the series in the case of n = 0.
And keep in mind, as with all recursive functions, very large values of n will cause a stack overflow.
Here are a couple of resources:
Math is fun
"Yes you can! But you need to get into a subject called the "Gamma
Function", which is beyond this simple page.
Half Factorial
But I can tell you the factorial of half (½) is half of the square
root of pi = (½)√π, and so some "half-integer" factorials are:"
More specifically you want the Gamma Function
Apache commons has an implementation of this function.
Discussion on Math Exchange
And here is an implementation from Princeton
public class Gamma {
static double logGamma(double x) {
double tmp = (x - 0.5) * Math.log(x + 4.5) - (x + 4.5);
double ser = 1.0 + 76.18009173 / (x + 0) - 86.50532033 / (x + 1)
+ 24.01409822 / (x + 2) - 1.231739516 / (x + 3)
+ 0.00120858003 / (x + 4) - 0.00000536382 / (x + 5);
return tmp + Math.log(ser * Math.sqrt(2 * Math.PI));
}
static double gamma(double x) { return Math.exp(logGamma(x)); }
public static void main(String[] args) {
double x = Double.parseDouble(args[0]);
System.out.println("Gamma(" + x + ") = " + gamma(x));
System.out.println("log Gamma(" + x + ") = " + logGamma(x));
}
}
Calculating e^n recursively is very expensive. It is O(n^2) and it is hard to know when to stop. Instead I suggest you do it iteratively.
static final int runs = 20000;
static volatile int exp = 1;
static volatile int n = 18;
static volatile double dontOptimiseAway;
public static void main(String[] args) throws InterruptedException {
System.out.println("Math.exp(1)=" + Math.exp(1));
System.out.println("exp_iter(18)=" + exp_iter(18));
System.out.println("exp_recurse(18)=" + exp_recurse(18));
for (int t = 0; t < 3; t++) {
System.out.printf("exp(1), exp_iter(18), exp_recurse(18) took %,d / %,d / %,d ns on average%n",
timeMathExp(), timeExpIter(), timeExpRecurse());
}
}
public static long timeMathExp() {
long start = System.nanoTime();
for (int i = 0; i < runs; i++)
dontOptimiseAway = Math.exp(exp);
return (System.nanoTime() - start) / runs;
}
public static long timeExpIter() {
long start = System.nanoTime();
for (int i = 0; i < runs; i++)
dontOptimiseAway = exp_iter(n);
return (System.nanoTime() - start) / runs;
}
public static long timeExpRecurse() {
long start = System.nanoTime();
for (int i = 0; i < runs; i++)
dontOptimiseAway = exp_recurse(n);
return (System.nanoTime() - start) / runs;
}
public static double exp_iter(int n) {
double exp = 0, x = 1;
for (int i = 2; i <= n; i++)
exp += (x /= i);
return 2 + exp;
}
public static double exp_recurse(int n) {
return n <= 0 ? 1 : 1.0 / fact(n) + exp_recurse(n - 1);
}
public static double fact(int n) {
return n <= 1 ? 1 : n * fact(n - 1);
}
prints
Math.exp(1)=2.718281828459045
exp_iter(18)=2.718281828459045
exp_recurse(18)=2.7182818284590455
exp(1), exp_iter(18), exp_recurse(18) took 111 / 191 / 760 ns on average
exp(1), exp_iter(18), exp_recurse(18) took 75 / 78 / 558 ns on average
exp(1), exp_iter(18), exp_recurse(18) took 69 / 66 / 552 ns on average
write the code as below and call it from main class.
public static double recursiveFun(double value){
if (value==1)
return 1.0;
if (value==2){
return (1/(value-1) + 1/value);
}
else
return recursiveFun(value-1) + 1/value;
}

Summing array values java

I'm feeding in an array of length 8 say if trials is 100 it might be of the form 93 5 2 0 0 0 0 0, but whatever the values I have in the array I only get 0.6 back. If anyone can see if I'm making a stupid error that would be great. I've tried it with a for loop but keep getting 0.6.
static void getMetric(int[]a, int trials){
double metric = 0;
int i =0;
while(i<8){
if(i==0){
double x = (a[0] / trials) - (2 / 15);
metric += Math.abs(x);
i++;
}
else if(i>0 && i<7){
double x = (a[i] / trials) - 0.1;
metric += Math.abs(x);
i++;
}
else{
double x = (a[7] / trials) - (2 / 15);
metric += Math.abs(x);
System.out.println(""+metric);
i++;
}
}
}
You use integer division ( 5 / 3 = 1; 2 / 15 = 0).
So instead of a[0] / trials, you should have a[0] / (double) trials;
Instead of 2 / 15 you should have 2 / 15.0 etc.
It looks like you need double-division and not int-division. Remember:
int a = 96;
int b = 100;
double c = a / b; //will be 0.0!
so the following program should do the same, but more correct, I think (and shorter):
static void getMetric(int[] a, int trials){
double metric = Math.abs((((double)a[0]) / trials) - (2 / 15));
for (int i = 1; i < 7; i++) {
metric += Math.abs((((double)a[i]) / trials) - 0.1);
}
metric += Math.abs((((double)a[7]) / trials) - (2 / 15));
System.out.println(""+metric);
}
and that one is even more reable and robust:
static void getMetric(int[] a, int trials){
double metric = calcMetricDiff(a[0], trials, 2.0 / 15.0);
for (int i = 1; i < a.length - 1; i++) {
metric += calcMetricDiff(a[i], trials, 0.1);
}
metric += calcMetricDiff(a[a.length-1], trials, 2.0 / 15.0);
System.out.println(""+metric);
}
private static double calcMetricDiff(double val, int trials, double diff) {
return Math.abs((val / trials) - diff);
}

RandomizedQuickSort method for arrays

IS there RandomizedQuickSort method in java API? OR we should write its code ourselves?
thanks
Unless you know that Arrays.sort() is not going to work for you, I suggest you use that. Otherwise I suggest you test any alternative is as good as it suggests.
I added the following to the source suggested by #org.life.java as well as a shuffle()/sort() methods which should be both randomised and quicksorted.
long runTimeNS = 2 * 1000 * 1000 * 1000L;
for (int i = 0; i < 3; i++) {
long start = System.nanoTime();
long r;
for (r = 1; r < runTimeNS; r++) {
Arrays.sort(list7.clone());
if (System.nanoTime() - start > runTimeNS) break;
}
long time = System.nanoTime() - start;
System.out.println("Average Arrays.sort() time " + time / r / 1000 + " us.");
long start1 = System.nanoTime();
for (r = 1; r < runTimeNS; r++) {
List<Integer> list = new ArrayList<Integer>();
for (int j : list7) list.add(j);
Collections.shuffle(list);
Collections.sort(list);
int[] ints = new int[list.size()];
for (int j = 0; j < list.size(); j++) ints[j] = list.get(j);
if (System.nanoTime() - start1 > runTimeNS) break;
}
long time1 = System.nanoTime() - start1;
System.out.println("Average shuffle/sort time " + time1 / r / 1000 + " us.");
long start2 = System.nanoTime();
for (r = 1; r < runTimeNS; r++) {
qrsort(list7.clone());
if (System.nanoTime() - start2 > runTimeNS) break;
}
long time2 = System.nanoTime() - start2;
System.out.println("Average qrsort() time " + time2 / r / 1000 + " us.");
}
and it prints
Average Arrays.sort() time 477 us.
Average shuffle/sort time 5964 us.
Average qrsort() time 36155 us.
Average Arrays.sort() time 474 us.
Average shuffle/sort time 5894 us.
Average qrsort() time 35078 us.
Average Arrays.sort() time 480 us.
Average shuffle/sort time 6211 us.
Average qrsort() time 34790 us.

Overcoming heap overflow issues

I tried to solve problems from Project Euler. I know my method would work logically (it returns answers to the small scale problem almost instantly). However, it scales horribly. I already attempted changing the .ini file, but to no avail.
Here's my code:
public class Number28 {
static int SIZE = 101; //this should be an odd number, i accidentally posted 100
/**
* #param args
*/
public static void main(String[] args) {
double start = System.currentTimeMillis();
long spiral[][]= spiral(SIZE);
long sum = 0;
for(int i = 0; i < SIZE; i++)
{
sum += spiral[i][i];
sum += spiral[i][SIZE - 1 - i];
}
System.out.println(sum - 1);
double time = System.currentTimeMillis() - start;
System.out.println(time);
}
public static long[][] spiral(int size){
long spiral[][]= new long[size][size];
if(size == 1){
spiral[0][0] = 1;
return spiral;
}
else{
long subspiral[][]= new long[size - 2][size - 2];
subspiral = spiral(size - 2);
for(int r = 0; r < size - 2; r++){
for(int c = 0; c < size - 2; c++){
spiral[r + 1][c + 1] = subspiral[r][c];
}
}
long counter = subspiral[0][size - 3];
for(int r = 1; r < size ; r++){
counter++;
spiral[r][size - 1] = counter;
}
for(int c = size - 2; c >= 0; c--){
counter++;
spiral[size - 1][c] = counter;
}
for(int r = size - 2 ; r >= 0 ; r--){
counter++;
spiral[r][0] = counter;
}
for(int c = 1; c < size ; c++){
counter++;
spiral[0][c] = counter;
}
return spiral;
}
}
}
Here's the edited code, worked like a gem:
public class Number28 {
static int SIZE = 1001;
static long spiral[][]= new long[SIZE][SIZE];
/**
* #param args
*/
public static void main(String[] args) {
double start = System.currentTimeMillis();
long spiral[][]= spiral(SIZE);
long sum = 0;
for(int i = 0; i < SIZE; i++)
{
sum += spiral[i][i];
sum += spiral[i][SIZE - 1 - i];
}
System.out.println(sum - 1);
double time = System.currentTimeMillis() - start;
System.out.println(time);
}
public static long[][] spiral(int size){
if(size == 1){
spiral[SIZE / 2][SIZE / 2] = 1;
return spiral;
}
else{
long subspiral[][]= spiral(size - 2);
int edge = (SIZE - size) / 2;
long counter = subspiral[edge + 1][edge + size - 2];
for(int r = 1; r < size ; r++){
counter++;
spiral[edge + r][edge + size - 1] = counter;
}
for(int c = size - 2; c >= 0; c--){
counter++;
spiral[edge + size - 1][edge + c] = counter;
}
for(int r = size - 2 ; r >= 0 ; r--){
counter++;
spiral[edge + r][edge] = counter;
}
for(int c = 1; c < size ; c++){
counter++;
spiral[edge][edge + c] = counter;
}
return spiral;
}
}
}
As a general piece of Project Euler advice, if your solution doesn't scale, there's almost certainly a better way to solve it. If you've used the same type of solution on an earlier problem you can go through the posts from other users on the earlier question to get ideas for solving the problem in different ways.
Not familiar with the Euler problems, but the horror appears to be your continual allocation and re-allocation of what are basically throwaway intermediate spirals, as you call down recursively to the base case.
Restructure so that you allocate your full spiral up front. Then call your recursive function, passing your full spiral in as a parameter by reference, along with a "level" parameter, which will change with each recursive call. E.g., initial call is with 100x100 spiral and level 100; next (recursive) call is with same spiral, by reference, and level 98. Operations within the function will all be done on the one-and-only-allocated spiral.
In a nutshell: allocate your data structure once, even if you operate on that data structure recursively.
The first problem I saw was a NegativeArraySizeException when running your program with SIZE = 100. I guess this has something to do with how each recursive call is decreasing the size by 2.
I believe that Steven's comment is right on the money. You are allocating the size of the array, them making a recursive call. This causes (SIZE - 1) number of arrays to be allocating, eating up all of your memory. Removing that one line should prevent any memory from being allocated until necessary.
Here is a simplified solution that doesn't store a matrix:
public class P28 {
private final static int N = 1001;
public static void main(String[] args) {
int limit = (N + 1) / 2;
int sum = -3;
int first = 4;
int r = 20;
for (int i = 1; i <= limit; i++) {
sum += first;
first += r;
r += 32;
}
System.out.println(sum);
}
}
Explanation:
Starting from 1 you can see 4 sums:
1 + 3 + 13 + 31 + 57 + ...
1 + 5 + 17 + 37 + 65 + ...
1 + 7 + 21 + 43 + 73 + ...
1 + 9 + 25 + 49 + 81 + ...
1 is added 4 times, this is why the default value for sum is -3.
Let's gather those sums:
4 + 24 + 76 + 160 + 276 + ...
(this is why first is 4 and r is 20 = 24 - 4)
You can observe that r increases by 32 per step ( 24 - 4 = 32 + 76 - 24 = 32 + 32 + 160 - 76 = ... ) and the actual number (first) increases by r.

Categories