Rust is the fastest, Miiao took measurements
Spoiler: Rust is faster and generally makes sense. (reference to article series by @humbug)
Joking aside, but we did not come here for this (I speak for myself). Not long ago, a friend of mine asked me to write FizzBuzz in Rust. It would seem, what is the problem? So the problem is not in what, but in whom – in me. I got a version that is both terribly concise and terribly verbose, and at the same time I decided to write approximately identical (in terms of logic, not appearance) implementations in several other languages, and then measure their performance on average hardware (Windows, 3.5 GHz, 4 GB of RAM) thought of it in order to understand the possibility of practical application of such solutions. In general, more to the point.
NOTE: There were five runs, but only the shortest and longest times, and the average proportional of all five runs, are presented.
General task
The task is extremely simple – to implement the function fb
, which will return “Fizz”, “Buzz”, “FizzBuzz”, or “Other(x)”, where x is a thirty-two-bit signed argument. Display execution results fb
for numbers in the sequence from 1 to 100000. In some pseudocode, it can be described as:
func fb(x: int): String {
var fizz = x % 3 == 0
var buzz = x % 5 == 0
if fizz and not buzz
return "Fizz\n"
else if not fizz and buzz
return "Buzz\n"
else if fizz and buzz
return "FizzBuzz\n"
else
return "Other(${x})\n"
}
entry {
var start = Time.now()
for i = 1 to 100000
print(fb(i))
var elapsed = Time.since(start).as_milliseconds() / 1000.0
print("100000 iterations in ${elapsed} seconds\n")
}
C
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char* FB[] = {"", "Buzz", "Fizz", "FizzBuzz"};
char* fb(char *s, int x) {
bool fizz = x % 3 == 0;
bool buzz = x % 5 == 0;
if (!fizz && !buzz) {
sprintf(s, "Other(%d)", x);
} else {
strcpy(s, FB[fizz << 1 | buzz]);
}
return s;
}
main() {
clock_t start = clock();
char s[15] = {0};
for (int i = 1; i <= 100000; i++) {
puts(fb(s, i));
}
printf("100000 iterations in %f seconds\n", (float) (clock() - start) / CLOCKS_PER_SEC);
}
The code is transparent as the tears of the baby that wrote it. It differs little from the original one, but is interesting in that instead of a trivial approach associated with a simple enumeration of options, we use bit shifts and or to select the desired string from an already prepared buffer. Many thanks to @rgimad for helping with optimizations.
Compilation Command
gcc fbc.c -Ofast
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
6.687 |
17.928 |
9.627 |
90 |
27 |
C++
#include <iostream>
#include <chrono>
#include <string>
#include <format>
#include <ranges>
auto fb(int x) -> std::string {
bool fizz = x % 3 == 0;
bool buzz = x % 5 == 0;
if (fizz && !buzz) {
return "Fizz";
} else if (!fizz && buzz) {
return "Buzz";
} else if (fizz && buzz) {
return "FizzBuzz";
} else {
return std::format("Other({})", x);
}
}
auto main() -> int {
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
for (int i : std::ranges::views::iota(1, 100001)) {
std::cout << fb(i) << std::endl;
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << std::format(
"100000 iterations in {} seconds",
(double) std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
.count() / 1000.0) << std::endl;
}
Many plus people blame me for the fact that my plus code is actually C code, so this time I decided to present the most modern solution using C++20 features.
Compilation command
g++ fbcpp.cpp -Ofast --std=c++20
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
18.179 |
27.418 |
21.606 |
16310 |
31 |
D
import std.format: format;
import std.stdio;
import std.range : iota;
import std.algorithm;
import std.datetime : MonoTime;
string fb (int x) {
bool fizz = x % 3 == 0;
bool buzz = x % 5 == 0;
if (fizz && !buzz) {
return "Fizz";
} else if (!fizz && buzz) {
return "Buzz";
} else if (fizz && buzz) {
return "FizzBuzz";
} else {
return format("Other(%d)", x);
}
}
void main() {
auto start = MonoTime.currTime();
iota(1, 100001)
.map!(fb)
.each!(writeln);
writefln("100000 iterations in %f seconds", (MonoTime.currTime() - start).total!"usecs"() / 1000000.0);
}
The di solution looks like a perfect version of the plus solution. I really like it, writing gave me great pleasure.
Compilation command
dmd fbd.d -O -release
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
8.034 |
18.79 |
10.043 |
730 |
27 |
Fortran
subroutine fb(i)
integer, intent(in) :: i
logical :: fizz, buzz
fizz = mod(i, 3) == 0
buzz = mod(i, 5) == 0
if (fizz .and. .not. buzz) then
write(*, '(a)') "Fizz"
else if (.not. fizz .and. buzz) then
write(*, '(a)') "Buzz"
else if (fizz .and. buzz) then
write(*, '(a)') "FizzBuzz"
else
write(*, '(a, i5, a)') "Other(", i, ")"
end if
end subroutine fb
program main
integer(kind = 4) :: i, start, end
real(kind = 4) :: elapsed
call SYSTEM_CLOCK(start)
do i = 1, 100000
call fb(i)
end do
call SYSTEM_CLOCK(end)
elapsed = end - start
write(*, '(a, f7.4, a)') "100000 iterations in ", elapsed / 1000.0, " seconds"
end program main
Here comes the old Fortran man! Frankly, writing code on this middle-aged handsome man was not the easiest, but rather pleasant and interesting process.
Compilation command
gfortran fbf.f08 -fimplicit-none -Ofast
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
4.531 |
13.438 |
6.256 |
1781 |
27 |
Rust
#[derive(Debug)]
#[repr(u16)]
enum FB {
Fizz = 1,
Buzz = 256,
FizzBuzz = 257,
Other(i32) = 0,
}
fn fb(x: i32) -> FB {
unsafe {core::mem::transmute((x % 3 == 0, x % 5 == 0, x))}
}
fn main() {
let start = std::time::Instant::now();
(1..=100000)
.map(fb)
.for_each(|x| println!("{x:?}"));
println!("100000 iterations in {} seconds", start.elapsed().as_millis() as f64 / 1000.);
}
How so! Almost forgot about the hero of the occasion! The code is very doubtful, because there are only two lines of logic (1, 11), and how many boilerplates… line 11, line 1 does the formatting.
Compilation command
cargo build -r
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
6.815 |
19.751 |
9.878 |
186 |
20 |
Swift
func fb(x: Int) -> String {
switch (x % 3 == 0, x % 5 == 0) {
case (true, false): return "Fizz"
case (false, true): return "Buzz"
case (true, true): return "FizzBuzz"
default: return "Other(\(x))"
}
}
let elapsed = ContinuousClock().measure {
(1...100000)
.map(fb)
.forEach({(i) -> Void in print(i)})
}
print("100000 iterations in \(elapsed) seconds")
Swift decided to visit his older brother, and at the same time compete with him. The solution is incredibly elegant and beautiful, bravo.
Compilation command
swiftc fbswift.swift -O -static
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
8.073 |
26.898 |
10,898 |
22 |
16 |
go
package main
import (
"fmt"
"time"
)
func fb(x int) string {
fizz := x % 3 == 0
buzz := x % 5 == 0
if fizz && !buzz {
return "Fizz"
} else if !fizz && buzz {
return "Buzz"
} else if fizz && buzz {
return "FizzBuzz"
} else {
return fmt.Sprint("Other(", x, ")")
}
}
func main() {
start := time.Now();
for i := 1; i <= 100000; i++ {
fmt.Println(fb(i))
}
elapsed := time.Since(start);
fmt.Printf("100000 iterations in %f seconds",
float64(elapsed.Nanoseconds()) / 1000000000.0)
}
Despite all my dislike for Go, I can’t say that it was unpleasant for me to write this code, and even vice versa.
Compilation Command
go build fbgo.go
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
5.912 |
16.001 |
11.636 |
1910 |
thirty |
PascalABC.NET
function fb(x: integer): string;
begin
var (fizz, buzz) := (x mod 3 = 0, x mod 5 = 0);
if fizz and not buzz then
result := 'Fizz'
else if not fizz and buzz then
result := 'Buzz'
else if fizz and buzz then
result := 'FizzBuzz'
else
result := string.format('Other({0})', x);
end;
begin
milliseconds();
range(1, 100000)
.select(fb)
.println(char(10));
writelnformat('100000 iterations in {0} seconds', millisecondsdelta() / 1000.0);
end.
PascalABC.NET is a unique language. It combines the features of imperative, object-oriented and functional programming in proportions that you would not expect from such a language.
Compilation Command
pabcnetc fbpas.pas
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
8.282 |
19.491 |
10.011 |
38 |
20 |
Dart
String fb(int x) {
bool fizz = x % 3 == 0;
bool buzz = x % 5 == 0;
if (fizz && !buzz)
return "Fizz";
else if (!fizz && buzz)
return "Buzz";
else if (fizz && buzz)
return "FizzBuzz";
else
return "Other($x)";
}
void main() {
final start = Stopwatch()..start();
for (int i = 0; i <= 100000; i++)
print(fb(i));
print("100000 iterations in ${start.elapsedMilliseconds / 1000.0} seconds");
}
Dart is a wonderful scripting language, I immediately liked it, it’s not for nothing that the most popular GUI framework – Flutter – is designed specifically for it.
Compilation Command
dart compile exe fbdart.dart
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
9.013 |
28.216 |
13.132 |
4837 |
19 |
PHP
<?php
function fb($x) {
$fizz = $x % 3 == 0;
$buzz = $x % 5 == 0;
if ($fizz && !$buzz) {
return "Fizz\n";
} else if (!$fizz && $buzz) {
return "Buzz\n";
} else if ($fizz && $buzz) {
return "FizzBuzz\n";
} else {
return sprintf("Other(%d)\n", $x);
}
}
$start = hrtime(true);
foreach (range(1, 100000) as $i) {
echo fb($i);
}
echo sprintf("100000 iterations in %f seconds\n", (hrtime(true) - $start) / 1e+9);
?>
Puff puff puff…
Run command (compilation is not supported)
php -f fbphp.php
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
5.497 |
26.465 |
11.459 |
85052 (PHP8) |
19 |
Kotlin
inline fun fb(x: Int): String {
val fizz = x % 3 == 0
val buzz = x % 5 == 0
if (fizz && !buzz)
return "Fizz"
else if (!fizz && buzz)
return "Buzz"
else if (fizz && buzz)
return "FizzBuzz"
else
return "Other($x)"
}
fun main() {
val elapsed = kotlin.system.measureTimeMillis {
for (i in 1..100000)
println(fb(i))
}.toDouble() / 1000.0
println("100000 iterations in $elapsed seconds")
}
Eh, Kotlin… love at first sight… we were so young, and all this passion…
Compilation command
kotlinc-native -opt fbkt.kt
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
13.666 |
16.69 |
15.302 |
540 |
20 |
Java
import java.util.stream.IntStream;
class Main {
public static void main(String[] args) {
FB fb = new FB();
double start = (double) System.currentTimeMillis();
IntStream range = IntStream.range(1, 100001);
range.forEach(x -> fb.fb(x));
double end = (double) System.currentTimeMillis();
double elapsed = (end - start) / 1000.0;
System.out.println(String.format("100000 iterations in %f seconds", elapsed));
}
}
class FB {
public static void fb(int x) {
FB fizzbuzz = new FB();
System.out.println(fizzbuzz.inner(x));
}
public static String inner(int x) {
boolean fizz = x % 3 == 0;
boolean buzz = x % 5 == 0;
if (fizz && !buzz) {
return "Fizz";
} else if (!fizz && buzz) {
return "Buzz";
} else if (fizz && buzz) {
return "FizzBuzz";
} else {
return String.format("Other(%d)", x);
}
}
}
Where without the prodigal mother Kotlin? Well, let’s see it in action…
Run command (compilation is not supported)
javac fbjava.java
java Main
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
8.579 |
36.771 |
23.131 |
305767 (JRE11) |
20 |
Python
from time import time
def fb(x: int) -> str:
fizz: bool = x % 3 == 0
buzz: bool = x % 5 == 0
if fizz and not buzz:
return 'Fizz'
elif buzz and not fizz:
return 'Buzz'
elif fizz and buzz:
return 'FizzBuzz'
else:
return f'Other({x})'
start = time()
for i in range(1, 100001):
print(fb(i))
print(f'100000 iterations in {time() - start} seconds')
Eh, python, python, what has life brought me to? Using you in benchmarks…
Run command (compilation is not supported)
py -m fbpy
results
Least, s. |
The largest, p. |
Average, p. |
Size, KB |
Length, lines |
6.891 |
24.966 |
15.979 |
287616 (CPython311) |
20 |
Conclusion and rating
Performance
Place |
Language |
Average time, s. |
1 |
Fortran |
6.256 |
2 |
C and Rust |
9.627 and 9.878 |
3 |
PascalABC.NET, D and Swift |
10.011, 10.043 and 10.898 |
4 |
PHP and Go |
11.459 and 11.636 |
5 |
Dart |
13.132 |
6 |
Kotlin and Python |
15.302 and 15.979 |
7 |
C++ |
21.606 |
8 |
Java |
23.131 |
Binary size
Place |
Language |
Size, KB |
1 |
Swift |
22 |
2 |
PascalABC.NET |
38 |
3 |
C |
90 |
4 |
Rust |
186 |
5 |
Kotlin |
540 |
6 |
D |
730 |
7 |
Fortran |
1781 |
8 |
go |
1910 |
9 |
Dart |
4837 |
10 |
C++ |
16310 |
eleven |
PHP (PHP8) |
85052 |
12 |
Python (CPython311) |
287616 |
13 |
Java (JRE11) |
305767 |
Conciseness (not only lines are taken into account)
Place |
Language |
Strings |
1 |
Swift |
16 |
2 |
Dart |
19 |
3 |
Kotlin |
20 |
4 |
Python |
20 |
5 |
Rust |
20 |
6 |
PascalABC.NET |
20 |
7 |
D |
27 |
8 |
go |
thirty |
9 |
C |
27 |
10 |
Fortran and C++ |
27 and 31 |
eleven |
Java |
34 |
Convenience of formatting (not only characters are taken into account)
Place |
Language |
Add. symbols |
1 |
Rust |
0 |
2 |
Kotlin and Dart |
1 |
3 |
Python and Swift |
3 |
4 |
D and PHP |
12 |
5 |
go |
16 |
6 |
C++ |
17 |
7 |
Java |
19 |
8 |
PascalABC.NET |
20 |
9 |
C |
24 |
10 |
Fortran |
27 |
Some results surprised me, others I predicted. Most of all, I was surprised by such a low position of pluses. Banter banter, and now I’m even somehow ashamed.
Let’s summarize:
-
Rust is the best;
-
PascalABC.NET knows how to surprise;
-
Python is concise but slow;
-
C gives a lot of scope to the imagination;
-
Dart, although scripted, is very fast and beautiful;
-
Kotlin fails a little, but that doesn’t stop it from being great;
-
D is on top, as always;
-
C ++ let us down … well, nothing, recovers, Corpsestraus said);
-
Go – unpretentious, but smart;
-
Fortran – grandfather, although he does not understand youth aesthetics, can still set the heat on even the fastest of modern languages;
-
Java is no longer the same;
-
PHP is the sonic of the scripting world;
-
Swift is loved by developers for a reason, Chris Lattner and Graydon Hore did a great job on it.
Please remember that benchmarks are subjective, do not take everything to heart, the primary purpose of creating this content is entertainment.
miiao.