How is multiplication faster than addition [duplicate] - java

This question already has answers here:
How do I write a correct micro-benchmark in Java?
(11 answers)
Closed 5 years ago.
I wanted to get some numbers on how fast is multiplication over addition. I wrote a simple code where I am multiplying 2 numbers, finding the time taken. Then I am adding the 2 numbers and find the time taken. The results are a bit disturbing. Before I show the results, here is the code
package com.np.fun;
import java.util.Scanner;
import org.apache.commons.lang3.time.StopWatch;
public class HowSlowIsMultiplication {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int x = scanner.nextInt();
int y = scanner.nextInt();
long z;
StopWatch stopWatchMultipy = new StopWatch();
stopWatchMultipy.start();
z = x*y;
stopWatchMultipy.stop();
System.out.println("Time taken for multiplication is : " + stopWatchMultipy.getNanoTime());
StopWatch stopWatchAdd_1 = new StopWatch();
stopWatchAdd_1.start();
for(int i =0 ;i <Math.min(x, y); i++){
z = z + Math.max(x, y);
}
stopWatchAdd_1.stop();
System.out.println("Time taken for adding in less for loops is : " + stopWatchAdd_1.getNanoTime());
StopWatch stopWatchAdd_2 = new StopWatch();
stopWatchAdd_2.start();
for(int i =0 ;i <Math.max(x, y); i++){
z = z + Math.min(x, y);
}
stopWatchAdd_2.stop();
System.out.println("Time taken for adding in more for loops is : " + stopWatchAdd_1.getNanoTime());
}
}
I tried this with varying values of x & y. Here is the output for x=10000 and y=5000 (all times are in naoseconds)
Time taken for multiplication is : 61593
Time taken for adding in less for loops is : 1622599
Time taken for adding in more for loops is : 1622599
As you can see, multiplication is several orders of magnitude faster than addition.
Any reasons for this?

First off, it's not clear what you're trying to measure, as you appear to be comparing a single multiplication against doing multiple additions in a loop. You shouldn't be surprised that the later is slower.
That being said, microbenchmarks like this are essentially random noise. A multiplication is just one instruction at the machine code level. It's likely to be swamped by any sort of branch or function call you do to measure the timing. In order to get accurate measurements at that level, you have to use special assembly instructions. You also have to account for out of order execution and pipelining, since modern CPUs execute multiple instructions simultaneously, especially in simple cases like integer multiplication.
Add on top of that all the abstractions of the JVM and of Java, and the enterprise is even more hopeless. Java compiles to bytecode, which is in turn interpreted or JIT compiled by the JVM. The JVM has wide latitude to do whatever optimizations it sees fit, so even operations that take different amounts of bytecode instructions may have little or no relation to the ultimate performance.

Related

Writing a Java program that uses threads to calculate an expression that ignores order of operations?

I am trying to author a Java program that uses threads to calculate an expression such as:
3 + 4 / 7 + 4 * 2
and outputs
Enter problem: 3 + 4 / 7 + 4 * 2
Thread-0 calculated 3+4 as 7
Thread-1 calculated 7/7 as 1
Thread-2 calculated 1+4 as 5
Thread-3 calculated 5*2 as 10
Final result: 10
In this exercise, we are ignoring order of operations. The expression is entered via user input. The goal is to get a separate thread to perform each calculation. I absolutely want each thread to perform each of the individual calculations, as I have listed above.
My honest, professional advice is don't try to use multithreading for this problem.
Learn to write clear, robust single-threaded code first. Learn how to debug it. Learn how to write the same thing in lots of different ways. It is only then that you can start to introduce the enormous complexity that is multithreading, and stand any chance of it being correct.
And learn, by reading about how to write multithreaded code correctly, what problems benefit from multithreading. This problem does not, because you need the result of the previous arithmetic operation as an input to the next.
I am only answering because of the terrible advice in comments to use global variables. Don't. This is not a good way to write multithreaded code, even in such a simple example. Even in single-threaded code, mutable global state is something which should be avoided if at all possible.
Keep your mutable state as tightly controlled as you can. Create a Runnable subclass which holds the operation you are going to perform:
class Op implements Runnable {
final int operand1, operand2;
final char oprator;
int result;
Op(int operand1, char oprator, int operand2) {
// Initialize fields.
}
#Override public void run() {
result = /* code to calculate `operand1 (oprator) operand2` */;
}
}
Now, you can calculate, say, 1 + 2 using:
Op op = new Op(1, '+', 2);
Thread t = new Thread(op);
t.start();
t.join();
int result = op.result;
(Or, you could have just used int result = 1 + 2;...)
So you can now use this in a loop:
String[] tokens = eqn.split(" ");
int result = Integer.parseInt(tokens[0]);
for (int t = 1; t < tokens.length; t += 2) {
Op op = new Op(
result,
result, tokens[t].charAt(0),
Integer.parseInt(tokens[t+1]));
Thread t = new Thread(op);
t.start();
t.join();
result = op.result;
}
All of the mutable state is confined to the scope of the op variable. If you, say, want to run a second calculation, you don't have to worry about what previous state is still hanging around: you don't have to reset anything before another run; you can invoke this code in parallel, if you want, without interference between runs.
But all of this loop could be written more cleanly - and faster - using a simple method call:
for (int t = 1; t < tokens.length; t += 2) {
result = method(
result,
result, tokens[t].charAt(0),
Integer.parseInt(tokens[t+1]));
}
Where method is a method containing /* code to calculate operand1 (oprator) operand2 */.

Why is my java program becoming gradually slower?

I recently built a Fibonacci generator that uses recursion and hashmaps to reduce complexity. I am using the System.nanoTime() to keep track of the time it takes for my program to print 10000 Fibonacci number. It started out good with less than a second but gradually became slower and now it takes more than 4 seconds. Can someone explain why this might be happening. The code is down here-
import java.util.*;
import java.math.*;
public class FibonacciGeneratorUnlimited {
static int numFibCalls = 0;
static HashMap<Integer, BigInteger> d = new HashMap<Integer, BigInteger>();
static Scanner fibNumber = new Scanner(System.in);
static BigInteger ans = new BigInteger("0");
public static void main(String[] args){
d.put(0 , new BigInteger("0"));
d.put(1 , new BigInteger("1"));
System.out.print("Enter the term:\t");
int n = fibNumber.nextInt();
long startTime = System.nanoTime();
for (int i = 0; i <= n; i++) {
System.out.println(i + " : " + fib_efficient(i, d));
}
System.out.println((double)(System.nanoTime() - startTime) / 1000000000);
}
public static BigInteger fib_efficient(int n, HashMap<Integer, BigInteger> d) {
numFibCalls += 1;
if (d.containsKey(n)) {
return (d.get(n));
} else {
ans = (fib_efficient(n-1, d).add(fib_efficient(n-2, d)));
d.put(n, ans);
return ans;
}
}
}
If you are restarting the program every time you make a new fibonacci sequence, then your program most likely isn't the problem. It might just be the your processor got hot after running the program a few times, or a background process in your computer suddenly started, causing your program to slow down.
More memory java -Xmx=... or less caching
public static BigInteger fib_efficient(int n, HashMap<Integer, BigInteger> d) {
numFibCalls++;
if ((n & 3) <= 1) { // Every second is cached.
BigInteger cached = d.get(n);
if (cached != null) {
return cached;
} else {
BigInteger ans = fib_efficient(n-1, d).add(fib_efficient(n-2, d));
d.put(n, ans);
return ans;
}
} else {
return fib_efficient(n-1, d).add(fib_efficient(n-2, d));
}
}
Two subsequent numbers are cached out of four in order to stop the
recursion on both branches for:
fib(n) = fib(n-1) + fib(n-2)
BigInteger isn't the nicest class where performance and memory is concerned.
It started out good with less than a second but gradually became slower and now it takes more than 4 seconds.
What do you mean by this? Do you mean that you ran this exact same program with the same input and its run-time changed from < 1 second to > 4 seconds?
If you have the same exact code running with the same exact inputs in a deterministic algorithm...
then the differences are probably external to your code - maybe other processes are taking up more CPU on one run.
Do you mean that you increased the inputs from some value X to 10,000 and now it takes > 4 seconds?
Then that's just a matter of the algorithm taking longer with larger inputs, which is perfectly normal.
recursion and hashmaps to reduce complexity
That's not quite how complexity works. You have improved the best-case and the average-case, but you have done nothing to change the worst-case.
Now for some actual performance improvement advice
Stop printing out the results... that's eating up over 99% of your processing time. Seriously, though, switch out "System.out.println(i + " : " + fib_efficient(i, d))" with "fib_efficient(i,d)" and it'll execute over 100x faster.
Concatenating strings and printing to console are very expensive processes.
It happens because the complexity for Fibonacci is Big-O(n^2). This means that, the larger the input the time increases exponentially, as you can see in the graph for Big-O(n^2) in this link. Check this answer to see a complete explanation about it´s complexity.
Now, the complexity of your algorithm increases because you are using a HashMap to search and insert elements each time that function is invoked. Consider remove this HashMap.

Minimization of number of itererations by adjusting input parameters in Java

I was inspired by this question XOR Neural Network in Java
Briefly, a XOR neural network is trained and the number of iterations required to complete the training depends on seven parameters (alpha, gamma3_min_cutoff, gamma3_max_cutoff, gamma4_min_cutoff, gamma4_max_cutoff, gamma4_min_cutoff, gamma4_max_cutoff). I would like to minimize number of iterations required for training by tweaking these parameters.
So, I want to rewrite program from
private static double alpha=0.1, g3min=0.2, g3max=0.8;
int iteration= 0;
loop {
do_something;
iteration++;
if (error < threshold){break}
}
System.out.println( "iterations: " + iteration)
to
for (double alpha = 0.01; alpha < 10; alpha+=0.01){
for (double g3min = 0.01; g3min < 0.4; g3min += 0.01){
//Add five more loops to optimize other parameters
int iteration = 1;
loop {
do_something;
iteration++;
if (error < threshold){break}
}
System.out.println( inputs );
//number of iterations, alpha, cutoffs,etc
//Close five more loops here
}
}
But this brute forcing method is not going to be efficient. Given 7 parameters and hundreds of iterations for each calculation even with 10 points for each parameter translates in billions of operations. Nonlinear fit should do, but those typically require partial derivatives which I wouldn't have in this case.
Is there a Java package for this sort of optimizations?
Thank you in advance,
Stepan
You have some alternatives - depending on the equations that govern the error parameter.
Pick a point in parameter space and use an iterative process to walk towards a minimum. Essentially, add a delta to each parameter and pick whichever reduces the error by the most - rince - repeat.
Pick each pareameter and perform a binary-chop search between its limits to find it's minimum. Will only work if the parameter's effect is linear.
Solve the system using some form of Operations-Research technique to track down a minimum.

Beginner's Java Code Help: Newton Raphson Square Root Loop

In my Java class for college we are learning about the Looping control structure, and we got an assignment to code a little program that I am guessing is supposed to give the square root of a number and keep on taking the square root until the difference or accuracy is met. Here are the instructions:
"Write a class called NewtonRaphson that can be used to find an approximate solution of sqrt(a) using Newton's method, for any positive real number.
Note: sqrt(a) can be expressed in functional notation as follows: f(x) = x2 – a,
From which f ' (x) = 2 * x,
Print the iteration sequence and the approximation for each iteration. (That is, in a tabular form).
Write a driver class called TestNewton. Use the following data to test the class NewtonRaphson.
• The initial guess is 5.0
• In this exercise, the process terminates when the difference between two consecutive approximations is less than 0.00005"
I have my code linked at the bottom here, the main class and the test class, but I am not getting the looping result I am just getting the same square root of 5 when I type in 5 after running the program. Can someone please tell me where I messed up on?
Thanks, I am really new to coding, and this took forever to make and I had to ask for some friends help.
Main Class: http://pastebin.com/eiUJFJjQ
Test Class: http://pastebin.com/sJ4dB5uZ
Or if you prefer the code here it is:
import java.text.NumberFormat;
import java.text.DecimalFormat;
public class NewtonRaphson {
static final double DIFFERENCE = 0.00005;
double n;
double x;
double derivative;
double function;
double xold;
double xnew;
int i;
public NewtonRaphson(double n2, int x2)
{
n=n2;
x=x2;
function = Math.pow(n, 2)-x;
derivative = 2*n;
xnew=n-function/derivative;
xold=0;
}
boolean positive()
{
return (n >= 0);
}
public double findXNew(double xold2)
{
function = Math.pow(xold2, 2)-x;
derivative = 2*xold2;
return xold2-function/derivative;
}
public void findSqRtA()
{
i=0;
while(Math.abs(xnew-xold)> DIFFERENCE)
{
xold=xnew;
xnew=findXNew(xold);
i++;
System.out.println(this);
}
System.out.println("\nIteration completed, difference is less than 0.00005");
}
public String toString()
{
NumberFormat nf = NumberFormat.getInstance(); DecimalFormat df = (DecimalFormat)nf;
df.applyPattern("0.00000000");
return "The approximate value of the square root of "+x+" is " + xnew + "\n" +
"The number of iterations is " + i;
}
}
and
import java.io.Console;
import java.util.Scanner;
public class TestNewton {
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
System.out.println("Enter a number you would like to find the square root of");
int a = reader.nextInt();
NewtonRaphson nr = new NewtonRaphson(5.0, a);
nr.findSqRtA();
}
}
My output is this, but I want it to take the square root after each iteration's result.
Enter a number you would like to find the square root of
5
The approximate value of the square root of 5.0 is 2.3333333333333335
The number of iterations is 1
The approximate value of the square root of 5.0 is 2.238095238095238
The number of iterations is 2
The approximate value of the square root of 5.0 is 2.2360688956433634
The number of iterations is 3
The approximate value of the square root of 5.0 is 2.236067977499978
The number of iterations is 4
Iteration completed, difference is less than 0.00005
Newton-Raphson method is very interesting. You can use it to approximate real-valued function roots. x2 is only one of them. Check this fractals produced with Newton-Raphson method. So, do not underestimate Newton-Raphson.
Your code works. But your expectations are mistaken, you think that on every iteration you will update the guess. The code actually does it in the while loop.
You may do something like this, the epsilon may also be a parameter.
First, you give a large epsilon find a square root estimation.
Then input the last approximation with a slightly smaller epsilon, until you are satisfied with the result.
I think this is what you expect.
You can simplify the code. Check this code out.
Your code is actually producing the correct result for me. Therefore I'm not sure what the problem is.
For help with Newton's method you can refer to this article:
http://en.wikipedia.org/wiki/Newton's_method
Can you show us your output?
"I thought the program is supposed to take the square root of each new answer from the previous square root, it constantly takes the square root of 5. But I want it to take the square root of each iteration's result"
Oh, I see, that's because you have this:
NewtonRaphson nr = new NewtonRaphson(5.0, a);
Simply replace the 5.0 above with your previous number.

Multiplication time in BigInteger

My mini benchmark:
import java.math.*;
import java.util.*;
import java.io.*;
public class c
{
static Random rnd = new Random();
public static String addDigits(String a, int n)
{
if(a==null) return null;
if(n<=0) return a;
for(int i=0; i<n; i++)
a+=rnd.nextInt(10);
return a;
}
public static void main(String[] args) throws IOException
{
int n = 10000; \\number of iterations
int k = 10; \\number of digits added at each iteration
BigInteger a;
BigInteger b;
String as = "";
String bs = "";
as += rnd.nextInt(9)+1;
bs += rnd.nextInt(9)+1;
a = new BigInteger(as);
b = new BigInteger(bs);
FileWriter fw = new FileWriter("c.txt");
long t1 = System.nanoTime();
a.multiply(b);
long t2 = System.nanoTime();
//fw.write("1,"+(t2-t1)+"\n");
if(k>0) {
as = addDigits(as, k-1);
bs = addDigits(as, k-1);
}
for(int i=0; i<n; i++)
{
a = new BigInteger(as);
b = new BigInteger(bs);
t1 = System.nanoTime();
a.multiply(b);
t2 = System.nanoTime();
fw.write(((i+1)*k)+","+(t2-t1)+"\n");
if(i < n-1)
{
as = addDigits(as, k);
bs = addDigits(as, k);
}
System.out.println((i+1)*k);
}
fw.close();
}
}
It measures multiplication time of n-digit BigInteger
Result:
You can easily see the trend but why there is so big noise above 50000 digits?
It is because of garbage collector or is there something else that affects my results?
When performing the test, there were no other applications running.
Result from test with only odd digits. The test was shorter (n=1000, k=100)
Odd digits (n=10000, k=10)
As you can see there is a huge noise between 65000 and 70000. I wonder why...
Odd digits (n=10000, k=10), System.gc() every 1000 iterations
Results in noise between 50000-70000
I also suspect this is a JVM warmup effect. Not warmup involving classloading or the JIT compiler, but warmup of the heap.
Put a (java) loop around the whole benchmark, and run it a number of times. (If this gives you the same graphs as before ... you will have evidence that this is not a warmup effect. Currently you don't have any empirical evidence one way or the other.)
Another possibility is that the noise is caused by your benchmark's interactions with the OS and/or other stuff running on the machine.
You are writing your timing data to an unbuffered stream. That means LOTS of syscalls, and (potentially) lots of fine-grained disc writes.
You are making LOTS of calls to nanoTime(), and that might introduce noise.
If something else is running on your machine (e.g. you are web browsing) that will slow down your benchmark for a bit and introduce noise.
There could be competition over physical memory ... if you've got too much running on your machine for the amount of RAM.
Finally, a certain amount of noise is inevitable, because each of those multiply calls generates garbage, and the garbage collector is going to need to work to deal with it.
Finally finally, if you manually run the garbage collector (or increase the heap size) to "smooth out" the data points, what you are actually doing is concealing one of the costs of multiply calls. The resulting graphs looks nice, but it is misleading:
The noisiness reflects what will happen in real life.
The true cost of the multiply actually includes the amortized cost of running the GC to deal with the garbage generated by the call.
To get a measurements that reflect the way that BigInteger behaves in real life, you need to run the test a large number of times, calculate average times and fit a curve to the average data-points.
Remember, the real aim of the game is to get scientifically valid results ... not a smooth curve.
If you do a microbenchmark, you must "warm up" the JVM first to let the JIT optimize the code, and then you can measure the performance. Otherwise you are measuring the work done by the JIT and that can change the result on each run.
The "noise" happens probably because the cache of the CPU is exceeded and the performance starts degrading.

Categories

Resources