Click here to Skip to main content
15,942,580 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm studying C++ after a few years studying Java, so I'm doing several simple test to compare how works each language using the same code in both.
I have ever heard that C++ is faster than Java, but my codes aren't. For example, a program that looks for primes numbers in the range you choose take 20 seconds in C++ against the 76 milliseconds it takes in Java for a range of 50 000.
The programs save the primes in an Vector / ArrayList and determine if the new number is prime using it, exaclty the same algorithm in both.

Java
static boolean comprobarPrimacidad(int n) {
        Iterator<Integer> it = primos.iterator();
        boolean primo = true;
        do {
            if((n%it.next()) == 0) primo = false;
        } while((primo == true) && (it.hasNext()));
        
        if(primo) primos.add(n);
        return primo;}


C#
bool calcularPrimalidad(unsigned int numero) {

	bool primo = true;
	vector<unsigned int>::iterator it = primos.begin();

	do {

		if ((numero % *it) == 0) primo = false;
		it++;
	} while ((it != primos.end()) && primo == true);

	if (primo == false) return false;

	primos.push_back(numero);
	return true;
}


Have I forgotten something? Thank you so much!
I'm using Visual Studio 2016 for C++ and Netbeans for Java

What I have tried:

I have tried to write both again and again, always getting the same result. I have done the same test outside the debugger in both case.
Posted
Updated 6-Apr-16 6:21am
Comments
Richard MacCutchan 6-Apr-16 5:41am    
How are you timing these tests?
Javier Ramírez Domínguez 6-Apr-16 5:43am    
I'm using currentTimeMillis in Java and chrono in C++
Jochen Arndt 6-Apr-16 5:43am    
You did not told us how you are measuring the execution time (e.g. when testing program execution startup and I/O is included).

There also differences between the code.
I don't know Java but

if((n%it.next()) == 0) primo = false;

should not be identical to

if ((numero % *it) == 0) primo = false;
it++;

because the Java code uses the next element while the C++ code uses the actual one. So the Java codes requires one iteration less (and produces probably wrong results).

Also the while statements uses reversed conditions which makes the C++ code execute one more statement when breaking before reaching the end.
Javier Ramírez Domínguez 6-Apr-16 5:58am    
The Iterators work in a different way in Java than in C++. The fist time you use it.next() in java, you get the array's first element and it puts the "pointer" in the next element. In C++ you need to do it manually, but in both codes the result is the same.
Maybe the iterators are the responsible of the delay, but I'm not totally sure It could cause this impact.
Jochen Arndt 6-Apr-16 6:26am    
Thank you for that information.

C++ can be tricky. If you have a vector there are two methods to access an element:
vector.at(index) and vector[index]
The first is much slower because it does a boundary check and the last is fast but results in access vioaltions when using an invalid index.
Using an iterator should be inbetween regarding the speed.

However, to reproduce the results you should show your complete programs.

I tried (on my Lubuntu Box) the following programs:
Java
import java.util.*;

class Primes
{

  static java.util.ArrayList<Integer> primos;

  static boolean comprobarPrimacidad(int n)
  {
    Iterator<Integer> it = primos.iterator();
    boolean primo = true;
    do
    {
          if((n%it.next()) == 0) primo = false;
    } while((primo == true) && (it.hasNext()));

    if(primo) primos.add(n);
    return primo;
  }


  public static void main( String [] args)
  {
    primos = new java.util.ArrayList<Integer>();

    int n=2;
    primos.add(n);
    while ( primos.size() < 50000)
    {
      ++n;
      comprobarPrimacidad(n);
    }
  }
}


C++
 #include <vector>
 using namespace std;

vector <unsigned int> primos;

bool calcularPrimalidad(unsigned int numero) {

  bool primo = true;
  vector<unsigned int>::iterator it = primos.begin();

  do {

    if ((numero % *it) == 0) primo = false;
    it++;
  } //while ((it != primos.end()) && primo == true);
  while (primo == true && it != primos.end());

  if (primo == false) return false;

  primos.push_back(numero);
  return true;
}


int main()
{
  unsigned int n=2;
  primos.push_back(n);
  while ( primos.size() < 50000)
  {
    ++n;
    calcularPrimalidad(n);
  }

}


with the following execution times:
Java    	0m8.573s
C++     	0m25.919s
C++ -O3  	0m4.416s



Compiler optimization (-O3 for g++) apparently plays a major role.
 
Share this answer
 
Comments
Jochen Arndt 6-Apr-16 8:10am    
My 5 for your proving.
CPallini 6-Apr-16 15:25pm    
Thank you.
[no name] 6-Apr-16 9:42am    
A 5.
CPallini 6-Apr-16 15:25pm    
Thank you.
Aescleal 11-Apr-16 7:35am    
Have a 5 but your results make me wonder where the questioner got his original Java timing of 76ms from...
You're comparing apples to oranges. First, the code you've written to find prime numbers is naively inefficient. You're not taking into account what's going on behind the scenes in either language and you're actually playing to the weaknesses of both languages.

An implementation that I wrote in VB.NET will generate 6 million primes in under 2 seconds on 5 year old hardware. It's not the languages you used, but the code you wrote that's the problem.
 
Share this answer
 
Comments
Javier Ramírez Domínguez 6-Apr-16 12:28pm    
I know there is better ways to check is a number is prime, as Miller–Rabin, for example, I wanted to know how the language deal with a high memory and calculation work. In this code, the computer have to check if the number is prime reading the memory and save (and resize) it if the number is.
Dave Kreskowiak 6-Apr-16 14:52pm    
OK, but that's not what your original question is saying. You're asking why the CODE is so much slower. You're not mentioning reallocation performance at all and, frankly, your code is not the same between the two tests because of the differences in memory management between java and C. A lot of the difference is in the underlying code that you didn't write that manages the lists.

For example, take an array of 50000 elements and add another element to it. In C, arrays are immutable. Once allocated they cannot be expanded or contracted. A new array of memory has to allocated and the contents of the old array copied to it then the old array is freed. If you're expanding the array by 1 each time through the loop, you're copying the same data over and over again a LOT.

I can't speak for how Java works and it may do something behind the scenese differently than C does it.

Preallocate the arrays for an appropriate size and you eliminate a large part of the performance differnce.

Again, the problem is in the code you wrote, not with the language.

[no name] 6-Apr-16 16:52pm    
"First, the code you've written to find prime numbers is naively inefficient": What this does Count in case it is same inefficient in both cases?

Also your other arguments do not really convince. "Preallocate the arrays for "... in case Java does handle it better than an Explanation why c++ does not.

So the 3 is from my side.

BTW: I'm 95% working with c++, but I don't defend it :-)
Such an enormous difference in performance can only be accounted for by a serious performance bottleneck in the C++ version. This is most likely caused by an accumulation of memory allocations as the array grows to 50,000 one element at a time. In the C# version, that amount of memory will have been pre-allocated as managed heap. You can pre-allocate the vector in C++ too and you should make the effort to do so if you know it is likely to grow so big.

Don't use push_back() to grow a vector to 50,000! You force it to run the memory allocation algorithm every time you add an element. Presize the vector or initialise it to grow in decent chunks, say 500 elements at a time, and then see what result you get.
 
Share this answer
 
Comments
Philippe Mori 6-Apr-16 12:59pm    
Wrong advice. The vector size will increase by a factor (probably between 1.5 and 2) each time there is not enough memory and similar approach is probably used in Java and C#. Assuming a factor of 2, there would be 16 allocation if initial allocation is one element.
john morrison leon 6-Apr-16 15:27pm    
"The vector size will increase by a factor (probably between 1.5 and 2)". I have used this approach in my own code. A factor of 1.05 to 1.10 produces a mildly exponential growth rate that is quite practical. I didn't know that this was built in to std::vector.

The performance bottleneck has got to be in code that you can't see. The vector and its allocations is the firtst place I would look.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900