Comparing C ++ and C #

I was worried about C # speed when it comes to heavy computing, when you need to use the raw processor power.

I always thought that C ++ is much faster than C # when it comes to computing. So I did some quick tests. The first test calculates prime numbers <integer n, the second test calculates some pandigital numbers. The idea for the second test comes from here: Pandigital Numbers

C # calculation:

using System; using System.Diagnostics; class Program { static int primes(int n) { uint i, j; int countprimes = 0; for (i = 1; i <= n; i++) { bool isprime = true; for (j = 2; j <= Math.Sqrt(i); j++) if ((i % j) == 0) { isprime = false; break; } if (isprime) countprimes++; } return countprimes; } static void Main(string[] args) { int n = int.Parse(Console.ReadLine()); Stopwatch sw = new Stopwatch(); sw.Start(); int res = primes(n); sw.Stop(); Console.WriteLine("I found {0} prime numbers between 0 and {1} in {2} msecs.", res, n, sw.ElapsedMilliseconds); Console.ReadKey(); } } 

C ++ option:

 #include <iostream> #include <ctime> #include <cmath> int primes(unsigned long n) { unsigned long i, j; int countprimes = 0; for(i = 1; i <= n; i++) { int isprime = 1; for(j = 2; j < sqrt((float)i); j++) if(!(i%j)) { isprime = 0; break; } countprimes+= isprime; } return countprimes; } int main() { int n, res; cin>>n; unsigned int start = clock(); res = primes(n); int tprime = clock() - start; cout<<"\nI found "<<res<<" prime numbers between 1 and "<<n<<" in "<<tprime<<" msecs."; return 0; } 

When I ran the test, trying to find primes <less than 100,000, the C # variant completed in 0.409 seconds and the C ++ variant in 0.614 seconds. When I launched them in 1,000,000 C #, I finished in 6.039 seconds and C ++ in about 12.987 seconds.

Pandigital test in C #:

 using System; using System.Diagnostics; class Program { static bool IsPandigital(int n) { int digits = 0; int count = 0; int tmp; for (; n > 0; n /= 10, ++count) { if ((tmp = digits) == (digits |= 1 << (n - ((n / 10) * 10) - 1))) return false; } return digits == (1 << count) - 1; } static void Main() { int pans = 0; Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 1; i <= 123456789; i++) { if (IsPandigital(i)) { pans++; } } sw.Stop(); Console.WriteLine("{0}pcs, {1}ms", pans, sw.ElapsedMilliseconds); Console.ReadKey(); } } 

Pandigital test in C ++:

 #include <iostream> #include <ctime> using namespace std; int IsPandigital(int n) { int digits = 0; int count = 0; int tmp; for (; n > 0; n /= 10, ++count) { if ((tmp = digits) == (digits |= 1 << (n - ((n / 10) * 10) - 1))) return 0; } return digits == (1 << count) - 1; } int main() { int pans = 0; unsigned int start = clock(); for (int i = 1; i <= 123456789; i++) { if (IsPandigital(i)) { pans++; } } int ptime = clock() - start; cout<<"\nPans:"<<pans<<" time:"<<ptime; return 0; } 

The C # variant works for 29906 seconds and C ++ after about 36.298 seconds.

I did not touch any compilers, and both C # and C ++ programs were compiled with debugging options. Before I tried to run the test, I was worried that C # was significantly behind C ++, but now it seems that C # has a pretty big difference in speed.

Can someone explain this? C # is jitted and C ++ compiled as a native, so it’s normal that C ++ will be faster than the C # variant.

Thanks for answers!

I changed all the tests for the Release configuration.

First test (prime numbers)

C # (digits <100.0000): 0.189 seconds C ++ (digits <100.0000): 0.036 seconds

C # (nummbers <1,000,000): 5,300 seconds C ++ (nummbers <1,000,000): 1,166 seconds

Second test (pandigital numbers):

C #: 21.224 seconds C ++: 4.104 seconds

So, everything has changed, now C ++ is much faster. My mistake is that I checked the test for Debug configuration. Can I see a speed improvement if I run C # executables via ngen?

The reason I tried to compare C # and C ++ is because I know some of the basics of both, and I wanted to learn the API that works with the GUI. I thought WPF was good, so given that I am focused on the desktop, I wanted to know if C # can provide sufficient speed and performance when it comes to using the pure processor power to calculate various calculations (file archivers, cryptography, codecs, etc.), but it seems that C # cannot keep up with C ++ when it comes to speed.

So, I assume that I will stay with this question forever. There is a tough question about WPF, Win32, MFC , and I will find a suitable API.

+5
c ++ c # benchmarking
source share
10 answers

Why do you assume jitted code is slower than native code? The only speed limit would be actual jitter that occurs only once (generally speaking). Given a program with a 30 second runtime, we are talking about a fraction of the total cost.

I think you can mislead jitted code with interpreted code that is compiled in turn. There is a fairly significant difference between the two.

As others have pointed out, you also need to run it in release mode; debugging mode disables most optimizations, so both versions will be slower than they should be (but with different amounts).

Change I have to point out one more thing, which is that this line:

 for (j = 2; j <= Math.Sqrt(i); j++) 

It is incredibly inefficient and can interfere with benchmarking. You must calculate Math.Sqrt(i) outside the inner loop. This may slow down both versions by an equivalent amount, but I'm not sure if different compilers will perform different optimizations.

+9
source share

simple generator in C ++ is incorrect

i ^ (1/2) == i xor 0

^ is a bitwise xor operator and / is an integer division.

1st edit , it is correct but inefficient: Since I xor 0 == i, the sieve does not stop at sqrt (i), but at i.

2nd edit:

Screening can be done a little more efficiently. (You only need to calculate sqrt (n)). Here's how I applied Eratosthenes sieve for my own use (this is on C99):

 void sieve(const int n, unsigned char* primes) { memset(primes, 1, (n+1) * sizeof(unsigned char)); // sieve of eratosthenes primes[0] = primes[1] = 0; int m = floor(sqrt(n)); for (int i = 2; i <= m; i++) if (primes[i]) // no need to remove multiples of i if it is not prime for (int j = i; j <= (n/i); j++) primes[i*j] = 0; } 
+12
source share

You need to compile C ++ in release mode and enable optimization to get the performance results you are looking for.

+11
source share

This takes a lot longer because the algorithm is incorrect.

 for(j = 2; j < (i^(1/2)); j++) 

coincides with

 for(j = 2; j < (i^0); j++) 

coincides with

 for(j = 2; j < i; j++) 

i is much larger than sqrt (i). Considering only the runtime, it is an order of magnitude longer than it should be in a C ++ implementation.

Also, like everyone else, I don't think it makes sense to do performance testing in debug mode.

+6
source share

Recompile the C ++ program with full optimization enabled and repeat the tests. C # jit will optimize the code when it is placed so that you compare optimized C # /. NET code with non-optimized C ++.

+4
source share

First, never do such tests in debug mode. For meaningful numbers, always use the release mode.

JIT has the advantage of knowing which platform it runs on, while precompiled code may be suboptimal for the platform on which it runs.

+2
source share

This is a constant myth that the JIT compiler in managed code generates machine code that is much less efficient than the one generated by the C / C ++ compiler. Managed code usually wins when managing memory and floating point math, usually C / C ++ wins when the code optimizer can spend a lot more time optimizing the code. In general, managed code is about 80%, but it completely depends on 10% of the code in which the program spends 90% of its time.

Your test will not show this, you have not enabled the optimizer, and optimizing it is a bit wrong.

+2
source share

guys, before comparing the speed of the program with one another, please, take the trouble to read several articles on processor instructions, assembly, cache management, etc. And the author is just ridiculously funny buddy. Checking the performance of debug collections.

Billy O'Neal - what is the difference between distributing a large buffer and using only a small part of it and using a dynamically allocated thing, for example, a vector in low-language words? When a large buffer has been allocated, no one worries about unused things. No additional support operations are required. While for dynamic things, such as a vector - a constant check of the boundaries of memory is not required to bypass it. Remember that C ++ programmers are not just lazy (it's true, I admit), but they are also smart.

+1
source share

Both tests are invalid because you compiled without optimization.

The first test is pointless, even as a comparison of non-optimized behavior due to an error in your code; Math.Sqrt(i) returns the square root of i, i^(1/2) returns i - so C ++ does a lot more work than C #.

More generally, this is not very useful - you are trying to create a synthetic test that has little to do with actual use.

0
source share

How about this:

 for(sqrti = 1; sqrti <= 11112; sqrti++) { int nexti = (1+sqrti)*(1+sqrti) for (i = sqrti*sqrti; i < nexti; i++) { int isprime = 1; for(j = 2; j < sqrti; j++) if(!(i%j)) { isprime = 0; break; } } 

} countprimes + = isprime; }

0
source share

All Articles