Ask HN: Why is JavaScript fast than C++ for simple calculations?

1 points by y42 ↗ HN
Just for fun, like for playing around, I tried improving a simple algorithm to find prime numbers in Python.

I was able to improve the speed from 6 seconds with a simple algorithm to 33 milliseconds with a more improved algorithm (looking for all primes up to 50k here, a more detailed description can be found there [1][2], this is the simple "algorith" - not much surprising:

    def isPrime(number):
        for i in range(2, number):
    
            if (number % i) == 0:
                return False
        
        return True
So I tried the same for JavaScript. The simple algorithm took 212 milliseconds, the improved one finished after 3 milliseconds.

So I wondered, what else can I test? I increased the upper bounds to 100 Mio. JavaScript took around 40 seconds. Using Cything I was able improve the running time to 70 seconds.

And I also tried Rust and C++ (disclaimer: I'm not a Rust or C++ developer!)

Rust was a desaster, I had to stop it after 5 Minutes. The first compiliation for C++ leads to a algorithm that tooks 70 seconds - almost double the time as JavaScript! After a little research I found out, that I can tune the compiling a little, which leads to a running time of 40 seconds.

So, still I wonder, in simple words: How can JavaScript be as fast as C++? (which probably only applies to simple mathmatics...)

[1] https://nickyreinert.medium.com/how-to-find-prime-numbers-fast-8d0f7e8bd80f

[2] https://nickyreinert.medium.com/javascript-how-to-find-prime-numbers-fast-cbcf6bd62e3d

9 comments

[ 2.9 ms ] story [ 25.3 ms ] thread
Maybe try the JS version without JIT, I suspect it might be highly optimized by the compiler. But the ratio seens way off, as sister comment states. Haven't looked into the code and am not a C++ or Rust expert, but maybe there is something fundamentally wrong there? Sounds like memory leak or issues with recursion.

Even if not, of course ahead-of-time compilation is not designed for a cold start. Haven't read the linked posts (including compilation time would be stupid)

Of course without compilation time. ;)
Are the C++ and JavaScript using all your procesor at 100%?

A few month ago I had to fight with Python (+ numba) so convince the compiler to parallelize some unusual matrix operation.

Nope, I tried this for Python but did not get it to run, will definitely try this for C++ and JavaScript. Thanks!
> (disclaimer: I'm not a Rust or C++ developer!)

You have not shown the Rust or C++ code, nor how you compiled it. Did you turn on optimizations?

If you want to know why some code is performing the way that it is, you have to give folks a way to reproduce what you did. There is simply not enough information to answer your question.

I assumed it was not important, it's just two loops with a modulo operation, but you are right, I made one mistake for Rust: I implemented a progress bar. This was slowing down the process tremendously. A clean script now takes around 400 seconds, but still way more than the other solutions, see here:

https://play.rust-lang.org/?version=stable&mode=debug&editio...

You linked to a playground that's in debug mode. If that's what you're measuring, you're absolutely going to be much slower. You need to compile with optimizations.

Additionally, while I don't have the time to dig into the specifics of the assembly here, your Rust code doesn't do the exact same thing as the JavaScript code. valand's version is a more direct translation. While it appears you tried a few things to optimize the function in this Rust version, ..= can be a performance hazard in microbenchmarks like this. I have no idea if that's relevant, but it's a good example of why it's important to actually show your code, how you compiled and ran it, and how you tested it.

But disregarding that, I still don't see how you're getting 400 seconds. You said you're testing up to 50,000 primes. In the playground that shows 0.02 seconds for me in debug, and 0.00 seconds in release.