简体   繁体   中英

java - How can i make this calculation faster?

My function is total += Math.sqrt(num) - Math.cbrt(num); I want to apply this to every number till the max value(starting from 0) i determine. So i wrote some code below which uses divide technique to calculate faster. How can i fasten this calculation? Code below( 8 threads ) takes 20 seconds to finish while non-thread takes 150 seconds to finish. I believe with forkjoinpool i can make it faster or maybe parallel streams ? How to implement it with them?

public class Main {

    private static int targetNum = Integer.MAX_VALUE;
    private static int threadCount = 8;
    private static double total = 0;
    public static void main(String[] args) {
    // write your code here
        DecimalFormat df2 = new DecimalFormat(".##");
        long time = System.currentTimeMillis();


        ExecutorService executor = Executors.newFixedThreadPool(threadCount);

        try {
            ArrayList<Future<Double>> futureList = new ArrayList<>();
            for(int a = 0; a < threadCount; a++){
                calculatorService ss = new calculatorService(a*(targetNum/threadCount) ,(a+1) *(targetNum/threadCount));
                futureList.add(executor.submit(ss));
            }
            for(int a = 0; a < threadCount; a++){
                total+= futureList.get(a).get();
            }

            System.out.println("Result= "+ df2.format(total) + "\nTime passed= " + ((System.currentTimeMillis() - time)/1000f));
            executor.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
class calculatorService implements Callable<Double>{

    private int start,end;

    public SqrtSummer(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public Double call(){
        double total = 0;
        for (int a = start; a < end; a++) {
            total += Math.sqrt(a) - Math.cbrt(a);
        }
        return total;
    }
}

Edit 1

futureList.get(a).get(); i had to do that in that way because i don't know the thread(core) count. Thus i can not write futureList.get(0).get() + futureList.get(1).get()..... I know till futureList.get(0).get() loop will wait but still they will be doing their job. My thread count is not fixed and can change any moment.

MultiThreading can benefit when your application is I/O intensive. However, this application is computing sensitive, maybe assign threadCount the number of your processor is best choice:

private static int threadCount = Runtime.getRuntime().availableProcessors();
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main {

    private static int targetNum = Integer.MAX_VALUE;
    private static int threadCount = Runtime.getRuntime().availableProcessors();
    private static double total = 0;
    public static void main(String[] args) {
    // write your code here
        DecimalFormat df2 = new DecimalFormat(".##");
        long time = System.currentTimeMillis();
        List<Future<Double>> futureList = new ArrayList<>();
        int lastSize=futureList.size();

        ExecutorService executor = Executors.newFixedThreadPool(threadCount);

        Runnable sumRunnable= () ->
        {   int sumCalculatedTill=0;
            while(!executor.isTerminated())
            {
                if(lastSize!=futureList.size())
                {
                    for(int i=sumCalculatedTill;i<futureList.size();i++)
                        try {
                            total+=futureList.get(i).get();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                    sumCalculatedTill=futureList.size();
                }
            }
            System.out.println("Result= "+ df2.format(total) + "\nTime passed= " + ((System.currentTimeMillis() - time)/1000f));
        };
        Thread thread=new Thread(sumRunnable);
        thread.start();

        try {


            for(int a = 0; a < threadCount; a++){
                calculatorService ss = new calculatorService(a*(targetNum/threadCount) ,(a+1) *(targetNum/threadCount));
                futureList.add(executor.submit(ss));

            }
            /*for(int a = 0; a < threadCount; a++){
                total+= futureList.get(a).get();
            }
*/

            executor.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
class calculatorService implements Callable<Double>{

    private int start,end;

    public calculatorService(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public Double call(){
        double total = 0;
        for (int a = start; a < end; a++) {
            total += Math.sqrt(a) - Math.cbrt(a);
        }
        return total;
    }
}

Just a thought. Let's discuss to optimize it more.

How to reduce your calculation to 1 microsecond? Easy.

Your grand total is : sum of the n square roots - sum of the n cubic roots

Math tips :

double sumOfSquareRoots = 2D * Math.pow((n + 0.5D), 1.5D) / 3D - 0.22474487139;

See https://arxiv.org/pdf/1204.0877.pdf for cubic roots :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM