C versus Java - Performance Test (Fibonacci of the first 50 integer numbers)

,

Well hello there, fellas, are you in for a nice ride along computer mathematical applications performance tests?

If no then you can go away 'cause we about to get kinda technical here. Here’s my entry on the “Just Do It Challenge”.

First I’ll link a Wikipedia article on Fibonacci to give you an intro: Fibonacci - Wikipedia

So yeah, long story short: you calculate the numbers based on the golden ratio.

Then let me tell you about two programming languages:

One is an oldie but certainly golden, we call it C, invented by Dennis Ritchie between 1972 and 1973 at Bell Laboratories to run on UNIX systems (according to wikipedia, you can check it out if you want), that compiles into binaries that are read by the machine (some people here might give you a better explanation, or even duck it yourself).

The other one is Java, developed initially by James Gosling at Sun Microsystems (later Oracle) and released at 1995 (it’s younger than me), that compiles into binaries that are read by a Virtual Machine (Java Virtual Machine - JVM) on top of the OS.

Basically C is praised for its performance and Java despised by the lack of it. There is a thread here in the forum to mock one of them.

I have just a little knowledge about both of these languages, I’m being honest, I know very little, but enough to pull out a program that will calculate and display the Fibonacci sequence from 0 to 50 (plus a \n [new line]) at the end and tell us how much time it spent doing just that. It is a recursive function inside of a “for” loop.

Before you ask “why 50?” I tell you: “because of time, my dear”. I tried calculating 100,000, then 1,000 and yet 100… it took way too long and I have other important stuff to do, this program is way heavier than I thought.

Here is the code for the C program:

    #include <stdio.h>
    #include <time.h>
    long fibonacci (long x)
    {
    if (x == 0)
    return 0;
    else if (x == 1)
	return 1;
    else
	return fibonacci(x-1) + fibonacci(x-2);
    }
    int main()
    {
    clock_t t;
    long i;
    t = clock();
    for (i = 0; i <=50; i++)
    {
    printf("%lu\n", fibonacci(i));
    }
    t = clock() - t;
    double time_taken = ((double)t)/CLOCKS_PER_SEC;
    printf("It took %f seconds to finish the program from 0 to 50.\n", time_taken);
    return 0;
    }

Yeah, it looks cool, right? And here’s the code for the Java program:

    class Fibonacci
    {
    public static void main(String[] args)
    {
    double startTime = System.currentTimeMillis();
    for (long i = 0; i <= 50; i++)
    {
    System.out.println(fibonacci(i));
    }
    double stopTime = System.currentTimeMillis();
    double elapsedTime = (stopTime - startTime) / 100;
    System.out.println("The program took around " + elapsedTime + " seconds to calculate the fibonacci of the first 50 numbers.");
    }
    static long fibonacci(long x)
    {
    if (x==0)
    {
    return 0;
    }
    else if (x==1)
    {
    return 1;
    }
    else 
    {
    return fibonacci(x-1) + fibonacci(x-2);
    }
    }
    }

These brackets for 1 line instructions might not be necessary but I stuffed’em there anyways, I’m too tired already to try it <3

Now for the system I used to test both:

Dell Inspiron n4050, i5 2450m with 4 gb of ram @ 1333 mHz, plugged into energy for standard boost.

OS: GNU/Linux Mint 19.2 Tina, updated just a few minutes before the tests, so we pretty fine.

GCC version: 7.4.0 (got it by downloading build-essential, cause vanilla mint has some issues with gcc)

Java version: OpenJDK 11 (Javac 11.0.4 - Java 11.0.4)

And into the long awaited results:

Java with the standard Javac -> 2,200.73 seconds to finish.

[EDIT_1] Guys I’m sorry but I made a huge mistake, it’s actually 220 seconds, if you take a look at the conversion on the code I forgot to add another 0, that means the conversion is WRONG, PLEASE PARDON ME! [/EDIT_1]

C time without optimization flag: 396.616303 seconds to finish.

C with the flag “-Ofast” (felt like sanic the herdgehog): 141.472849 seconds to finish (boy it was fast).

LONG STORY SHORT: Yeah, the memes are right, Java is fairly slower than C on demanding applications.

[EDIT_2] Considering the right time conversion to Seconds in JAVA it actually means a standard C program will be outperformed by a Java one, but the OPTIMIZED C PROGRAM WILL PERFORM BETTER [/EDIT_2]

Both applications let the CPU at around 30% and memory at 25%. Now for the sizes of the files:

Java text: 540 bytes
Java Class (the application itself): 1.2 kb
C text: 424 bytes
C standard compiling: 8.4 kb
C with sanic compiling (which I named fibonacciTurbo btw): 13.9 kb  

There are a few reasons, but I won’t get too technical on the OP, but basically is the JVM thing that runs above the OS and the Garbage Collector (probably, I’m no expert).

But there you have the code, feel free to try it yourself, specially if you have some beefier cpu/system.

I could study multithreading to try and optimize both even more, but I won’t right now… maybe later… maybe not… IDK

You’re waiting for the potato, right?

Here, have it:

Thanks for your time and feel free to correct me, yell at me, cuss, anything. But remember I’m no expert.

[EDIT_3]The OP was edited because I made a rookie mistake on time conversion and forgot to add another dividing ms to s. SORRY! [/EDIT_3]

13 Likes

Multithreading will be more lines than the programm you run. 2 ideas:

  1. Hardcore (don’t) or detect the threads you want to set up, then divide up the work and check when someone is done before handing the next task to the worker.
  2. Set up all the jobs you need to run, then just throw them at the scheduler and let code writen by smarter people figure it out.
1 Like

Just like with C, there are some command line arguments that you could pass to the Java executable when running it. You could also bypass the garbage collector in your code as well (don’t do this).

You may be able to shave a few seconds off the Java code by declaring an unsigned int, shot, or int, rather than a long in the for loop. That is the most basic optimization that you could do honestly. Anything else requires you to know some compile time or just in time, or code hacks to get C speed for this simple program.

The big thing is that C, especially with the Sonic flags compile right down to assembly and sometimes machine language. You will never get this with JVM even though that is what the JVM is written in (in parts at least) on certain platforms. Java shines better when you are doing larger workloads as speed is just not its thing. Data throughput on the other hand may be better in Java compared to C (without optimizations).

**Edit
C and Java are my go to languages. I am a CS nerd with a focus on Computation and Embedded design. Also natural language processing fits somewhere in there as well.

1 Like

Interesting result, but I’m not really surprised seeing that those languages have totally different objectives. C is the successor of Basic, when the hardware wasn’t as powerful and as vastly different from one system to another. Lacks all the creature comforts like handling the allocated memory for you in exchange for speed. Java on the other hand runs on everything that can understand Java, hardware agnostic. Has more creature comforts but that makes is slower.

1 Like

I would be interested in what the runtime for C++ is on this, as well as different methods of fibonacci calcs, you can do this with pointers and a while loop instead of a recursive function and it should have a smaller footprint. But yes the virtual machine makes simple java programs quite a bit slower than the lower level memory access you get with C. Another test I would do is to output the number of processor ticks rather than the time elapsed. Especially since using time.h in c/c++ is going to only output seconds and you aren’t going to be able to see ms iirc.

1 Like

just for shts and giggles, i reproduced that in batch:

@echo off
SETLOCAL EnableDelayedExpansion
set a=1
set b=1
 
echo %a%
echo %b%

for /l %%x in (0,1,50) do (
    SET /A "c=!a!+!b!"
    echo !c!
    set "a=!b!"
    set "b=!c!"
)

and timed it with Powershell:
image

I’m pretty sure i’ve gotten something wrong, so feel free to point out anything wrong with this.

Overall, your results “feel” really long. 150 Second for a computer to add up 50 Numbers recursively feels insanely slow. With the Batch Script above i can get to 1000 itterations in 0.4 Seconds.

2 Likes

The first iteration calls fibonnacci twice, the second iteration 4 times the third 8 times, 16, 32, …

That’s why it’s so slow. This slow method of implementing fibonacci is sometimes intentionally used when measuring runtimes because it’s very concise, somewhat realistic and yet computationally expensive.

So yeah, if your program is fast there’s definitely something wrong with it :smiley:

3 Likes

Ok, i reformatted the Java code a bit and now understood what’s going on. Thanks for pointing this out.
I’m surethis is doable in batch. I’ll see what i can come up with.

“minilight” is a tiny raytracer that has been ported to many languages, which makes it very interesting for performance comparisons:

http://www.hxa.name/minilight/#comparison

I’d love to see the results with newer compilers & programming languages. Pretty sure C & C++ should run at the same speed nowadays.

1 Like

System: 1700x, Win10

Processing:

//fibonacci
void setup(){
  calc(50); //specifies number of runs
}

void calc(int cycles){
for (long i = 0; i <= cycles; i++){
  println(fibonacci(i));
}
  print("time in miliseconds: " + millis());
}

long fibonacci(long x){
  if(x==0){
    return 0;
  }else if (x==1){
    return 1;
  }else{
    return fibonacci(x-1) + fibonacci(x-2);
  }
}

Julia:

startTime = time_ns()

function fibo(n)
  x,y = (0,1)
  for i = 1:n
    x,y = (y, x + y)
  end
  return x
end

for n=1:50 #number of runs
  println(fibo(n))
end

endTime = time_ns()
totalTime = (endTime - startTime)/1000000000 #convert from nanosec to sec
print("time taken: ", totalTime , " seconds")

I can’t get the C programm to run (compiled with GCC on Win10)

Language Time (in Seconds)
C (gcc -O0) 266
C (gcc -O3) 122
Java 211
Processing 213
Julia 0.05 (?)

Code and compiles: Fibonacci.zip (50.1 KB)

Have to see if I can get a friend of mine to rewrite this in Rust.
Edit:
RUST: (thanks buddy of mine)

use std::time::SystemTime;

fn fibonacci(n:u64) -> u64{
    if n == 0 {
        0
    }
    else if n == 1 {
        1
    }
    else {
        fibonacci(n-1) + fibonacci(n-2)
    }
}

fn main() {
    let start = SystemTime::now();
    for i in 1..51 {
        println!("{}", fibonacci(i));
    }
    let elapsed = start.elapsed();
    println!("Execution took {}s.", elapsed.unwrap().as_secs());
}

1 Like

So far i’ve got this:

@echo on
SETLOCAL EnableDelayedExpansion

for /l %%x in (0,1,2) do (
    echo "Itt %%x"
    call:fib %%x
)

:fib
    if %~1==0 (echo 0) else (
        if %~1==1 (echo 1) else (
            set /a "y=%~1-1"
            set /a "z=%~1-2"
            set /a "x=call:fib %y%+call:fib %z%"
            echo "!x!"
        )
    )

This doesn’t work as i can’t use call: in set. So i’m unable to assign the result of the function to a variable. If anyone has a clue on how to do this, i’d be gratefull.

1 Like

Wow, thanks for all the response, that was nice!

Let’s answer some questions:

And that’s why I love it so much. Will dive head down on it from now on, I simply fell in love hahah

Exactly, and that’s what makes Java the most common language in Brazil at least. Which is both good and bad. For commercial applications it is more than ok since you won’t be crunching some mad numbers like in this case.

Will try to implement in C++ as soon as I have time and will post the results here also. About the for loop: The intention is not to have the most optimal path, but to make a somewhat similar program to measure time itself. About the ms and seconds thing: I tried to convert the java System.time to seconds, it might not be very accurate but these 2,200 sec are actually 2,200,000 ms or something, but it’s in the code anyways.

YES and that’s why I did it. Was calculating the prime numbers from 1 to 100,000 before but got the same result in C and Java, it was not very resource-heavy(both before optimization [better code] where hovering around 43 seconds, but I managed to strip down a couple seconds in C after changing couple lines).

I’ll have to say I’m sorry but have never even tried batch… don’t even understand how it works actually, is it compiled to machine code or is it just talking to the win32 API?

Why are we using one scenario to try to prove one language better than another? These languages have 2 completely different use cases, and are built for completely different reasons. C is great if you want to do something simple and fast with no added functionality. Java is great when you need something to be distributed on any platform from a PC to a crockpot and work exactly the same on these very different architypes with full networking functionality.

2 Likes

We are just testing one scenario, and as both C and Java somehow found their way into datacenter use, it is only fair to compare them in calculations.

I agree that it’s a bit like comparing RAM usage on DOS 6.22 to Windows 10 while running Classic Doom. Technically the same Task, but the environment and capabilities of the underlying structure is fundamentally different.

IF you wanted to run Doom though, the test might be interesting. Not to determine which OS is better or more efficient though.

1 Like

Now let’s go for C++ (boi have I fell in love even more with it than C… that was unexpected…)

This is my first “real “program”” in C++ aside from some other minor stuff, and there are some changes that I did but won’t go back to the other ones: I put an integer on the for loop, makes it smaller and probably more performant, and that’s it.

C++ code:

#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
long fibonacci(int x)
{
if (x == 0)
return 0;
else if (x == 1)
return 1;
else
return fibonacci(x-1) + fibonacci(x-2);
}
int main()
{
auto start = high_resolution_clock::now();
for (int i = 0; i <= 50; i++)
cout<<fibonacci(i)<<endl;
auto stop = high_resolution_clock::now();
auto duration = duration_cast<seconds>(stop-start);
cout<<"The program took "<<duration.count()<<" seconds to finish from 0 to 50"<<endl;
}

And the results, this one is without optimization flags:

And here with -O2 flag, cause O3 and Ofast didn’t work, we got tails instead of sanic, but that was pretty fast already:

Compiler was G++, when I have some more time I boot up the laptop to check the version.

But we see it’s close to C, even without the max speed flag, that was nice.

I’m not using it to prove any language is better than another, it’s just a performance test in a math application. I don’t think any language is better than any other, they’re just different.

But I have to tell you, there are some major differences when talking about the runtime environment, and for me running things closer to the hardware seems better than on a layer on top of the OS… I intend to jump into electronics and robots stuff soon enough, I want to see code morphing into action, you know? Don’t think I’d like to be coding ERP for the rest of my life.

Hadn’t seen this before!

To run it on windows you’ll need to compile it with MingW, that’s their “version” of GCC, I also tried running a gcc compiled program in windows once and didn’t work.

Well of course it’s going to be better in any complex math function if all you want to do is math. It’s a primitive language. Beautiful in its simplicity. I went to school for C and C++ and I still find them functional and useful in modern applications. It just depends on what I’m using them for. If I want to access a database over a network, and have it post results to any users in many different formats, I would reach for the Eclipse icon and start writing a JDBC. This is a nearly irrelevant comparison because these languages are for different tasks, different use cases. Java is great for building a refrigerator that will order your groceries for you or a crock pot that will have dinner ready by the time you get home (given you don’t burn your house down, but that’s a whole different problem). C is what java is built on top of.

1 Like

Please don’t feel offended by the tests or this post, you’re the second person coming to me saying this.

This is just a comparison for fun, it was fun to me at least, and these are the two languages I’m more “well versed”.

This post won’t change anything on the real world, companies will not stop using java because they saw some random dude comparing it to C.

There’s no absolute better language, neither runtime environment.

I aim working with embedded systems and that’s why I love “touching bare metal”.

Just relax, dude, everything is okay.

3 Likes

You can use java8’s parallell streams for that.

class Fibonacci
{
	public static void main(String[] args)
	{
		double startTime = System.currentTimeMillis();

		java.util.stream.IntStream.range(0, 50).parallel().forEach( i -> {
			System.out.println(fibonacci(i));
		});

		double stopTime = System.currentTimeMillis();
		double elapsedTime = (stopTime - startTime) / 100;
		System.out.println("The program took around " + elapsedTime + " seconds to calculate the fibonacci of the first 50 numbers.");
	}

	static long fibonacci(long x)
	{
		return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
	}
}

Still taking forever

But, the main reason this is taking so long in the first place is your recursive function when you replace the fibonacci function with an iterative one, you’ll be MUCH MUCH FASTER be it c or java it does not matter.

class Fibonacci
{
	public static void main(String[] args)
	{
		double startTime = System.currentTimeMillis();

		java.util.stream.IntStream.range(0, 50).parallel().forEach( i -> {
			System.out.println(fibonacci(i));
		});

		double stopTime = System.currentTimeMillis();
		double elapsedTime = (stopTime - startTime) / 100;
		System.out.println("The program took around " + elapsedTime + " seconds to calculate the fibonacci of the first 50 numbers.");
	}

	static long fibonacci(long n) {
		if(n <= 1) {
			return n;
		}
		long fib = 1;
		long prevFib = 1;

		for(int i=2; i<n; i++) {
			long temp = fib;
			fib+= prevFib;
			prevFib = temp;
		}
		return fib;
	}
}

It’s now even faster than before if you remove the parallell.

That would be, because it is taking the program longer to create the tasks than to actually execute them.


Effectively, you’re not really even doing heavy compute here. You are just throwing a lot of longs onto your stack and then it get’s slow or you get an infamous StackOverflowException. That’s what you are testing here not how fast the languages can crush numbers, imo.

4 Likes