Language: EN

benchmark-count-one-billion

How long does it take to count to a trillion in different languages?

Recently, a meme with a capture of a table comparing speeds of different languages has gone viral on the Internet, adding all the numbers from one to a trillion (English, 1,000 billion) in a simple loop.

Of course, the thread has been filled with people giving their opinion, making their conjectures…although many of them have no basis. And, as usual, some comments are…let’s say “passionate”. Well, there was more hate than sense.

First of all, let it be clear that in my opinion this type of “my language is better than yours” discussions are quite childish. There are much more important aspects when choosing a language, and focusing on something like “count to 1 trillion faster” is very, very limited.

But well, most people love to talk about it and compare languages, and make them compete with each other. In fact, let’s confess that we all do it from time to time.

So let’s write an entry about it, with a minimum of rigor (as much as we can when we’re just going to count to a trillion).

Benchmark between languages

First of all, let it be clear that making a precise and representative benchmark is quite complicated. It depends on many factors, such as the hardware used, the specific implementation of each language, the applied optimizations, even the moment you catch the processor. It’s a whole world to make well-made benchmarks.

But well, that’s not interesting, what we want is to count to a trillion! So, let’s count to a trillion in different languages. As a benchmark, it’s still a crappy test, but… on the other hand, it’s still a test like any other.

So let’s compare,

  • C++, compiled with MVSC, in Debug / Release
  • C++, compiled with G++, with and without optimizations -O3
  • Go
  • Rust, compiled in Debug / Release mode
  • JavaScript executed on NodeJS
  • JavaScript executed on Chrome
  • Python

And the results are here, with the time in seconds (less is better),

LanguageTime (s)
C++ (G++ -O3)0
Rust (Release)0
C++ (MVSC Release)0.1
Go0.25
C# (Release)0.32
C++ (MVSC Debug)0.5
JS (NodeJS)0.45
C# (Debug)0.65
C++ (G++)1.3
JS (Chrome)4.35
Rust (Debug)6.46
Python40.46

Obviously, these times are only valid for my computer i5 Gen 12, Win10, at 2 in the morning, while listening to music on Spotify, and are only valid to compare between them.

If you run it on your computer, you will have different results. I’m seeing people sharing times among them as if everyone had the same computer, saying well, my “such test” gives me “so much”. And how should I know what computer you have! You are comparing apples and oranges. You will have to run all the tests and compare between them.

In any case, let’s put it in a nice little chart, and here it is,

lenguaje-comparativa-chart

Here with an enlargement at the bottom of the table (because Python is so slow that it ruins the whole graph, and you can’t see anything)

lenguaje-comparativa-chart-2

Things we will see. Python is the slowest, by a wide margin. Oh, what a surprise! We all knew that Python was slow, and that its purpose is not to be fast.

As for the fastest, C++ and Rust. Logical, because they are meant for that. In fact, in optimized mode (Release or -O3) the time is ZERO. Not “more or less small”… it’s ZERO. That’s because the compiler is smart enough to completely eliminate the loop, because it knows its value is N*(N+1)/2.

This is only possible because this benchmark is excessively simple, and the compiler can eliminate the loop. If the loop weren’t so simple, it couldn’t eliminate it. But well, this illustrates (again!) how important the role of the compiler and its optimizations is.

Also pay attention to the difference between compiling with Release, or Debug (optimized - not optimized). Rust without optimization takes 6 seconds, and C++ in G++ up to 1.3 seconds. That’s what “my language is very fast” means. Well yes… if you compile it well.

Many times you see people saying that C++ is very fast and “making fun” of JavaScript (for example)… but then they forget to use the -O3 flag. Then your C++ code is three times slower than the JavaScript code!

Continuing with C#, the darling of this holy house (my website), which gets 0.66 in Debug and 0.32 in Release. Again, the difference between Debug and Release is important, and in general a very good result.

However, I’m a little disappointed that the .NET compiler wasn’t able to detect that the loop is useless, and didn’t eliminate it like Rust and C++. Well, that’s what there is, see? This is how you accept a result, even when you don’t particularly like it.

On the other hand, I see a lot of people in the comments saying “it’s impossible for C# to beat C++“. Uh, yes, it is possible. I have seen it myself. Sometimes (not often, but sometimes) the C# code is faster than the C++ code. Don’t believe it? Look for JIT compiler on the internet, and you have reading and entertainment for a while.

JavaScript, in the browser is obviously a disaster. But in NodeJS it gets 0.45s, a very good result (point for Node). A good example that language is not the only thing that matters. In fact, the language is the least important. It’s the environment / compiler / interpreter that has the greatest influence on speed.

Almost always the language is linked to an execution environment and/or framework. But conceptually, they are independent, the language is an abstract concept. That’s why all languages get different times, depending on how you run them. This is one of the reasons why comparing “languages” doesn’t make much sense.

Finally, and I’ll finish the chatter, Go gets a very honorable 0.25s. Placing itself slightly faster than C#, and slightly slower than C++ and Rust. So there it is, if you like Go, it didn’t turn out bad in the comparison.

Conclusion

Conclusiooooon. Well, the results are what they are. Some will say “But my language can be optimized by doing…such and such thing! and whine whine whine”. Yes sure! All languages can be optimized in this life. But what has come out, is what comes out, in the “normal flow of language execution”.

Are you a fan of X language and don’t like that it came out slower than C++ / Rust? Well, my friend… deal with it 🤷. Don’t be a fan of a language, it doesn’t make sense. And the data is what it is. Don’t like the benchmark results? Perfect, do your own, share it with the community, and then we can all learn something 😙.

But above all, really, don’t take these things so, so seriously. They’re just comparisons between languages. It’s not a member of your family. It’s not someone who ran over your cat 🐈. You’re not a fan of a football match.

Each language has its characteristics. Defending one or the other, or making fun of one or the other, doesn’t make much sense. Also, in the real world things are much more complicated (and fun) than “count to a trillion”.

So be good, learn all the languages you can, and don’t go arguing with people. Take care and behave well 😘!

Code used

Here’s the code I’ve used, so you can try it on your computer, with no tricks.

C#

using System.Diagnostics;

Stopwatch stopwatch = Stopwatch.StartNew();

long suma = 0;
for (int i = 0; i <= 1000000000; i++)
{
    suma += i;
}

stopwatch.Stop();
TimeSpan duration = stopwatch.Elapsed;

Console.WriteLine(suma);
Console.WriteLine("Tiempo transcurrido: " + duration.TotalSeconds + " segundos");

C++

#include <iostream>
#include <chrono>

int main() {
    auto start = std::chrono::high_resolution_clock::now();
    
    long long suma = 0;
    for (int i = 0; i <= 1000000000; i++) {
        suma += i;
    }
    
    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> duration = end - start;
    
    std::cout << suma;
    std::cout << "Tiempo transcurrido: " << duration.count() << " segundos" << std::endl;
    
    return 0;
}

JavaScript

console.time("Tiempo transcurrido");

let suma = 0;
for (let i = 0; i <= 1000000000; i++) {
    suma += i;
}

console.timeEnd("Tiempo transcurrido");

Python

import time

start_time = time.time()

suma = 0;
for i in range(1000000000):
    suma += i

end_time = time.time()
duration = end_time - start_time

print(suma);
print("Tiempo transcurrido: ", duration, "segundos")

Rust

use std::time::Instant;

fn main() {
    let start_time = Instant::now();
    let mut sum: i64 = 0;

    for i in 1..=1_000_000_000 {
        sum += i;
    }

    let elapsed_time = start_time.elapsed();

    println!("La suma total es: {}", sum);
    println!("Tiempo transcurrido: {:?}", elapsed_time);
}
  • Debug with cargo run
  • Build with cargo run —release

Go

package main

import (
	fmt"
	"time"
)

func main() {
	startTime := time.Now()
	sum := 0

	for i := 1; i <= 1000000000; i++ {
		sum += i
	}

	elapsedTime := time.Since(startTime)

	fmt.Println("La suma total es:", sum)
	fmt.Println("Tiempo transcurrido:", elapsedTime)
}