要約

C++ だと 11.44 秒かかるものが Rust だと 18.36 秒もかかって遅い。なぜだ?

議論する内容

Leibniz 級数というものを使って円周率を計算するプログラムを Rust と C++ で実装して速度を比較する。実行時に級数の項の数を引数として渡して計算させる。うまくプログラムが書けていれば、Rust と C++/Clang ではほとんど性能が変わらないはずだが…

Rust でのコード・コンパイル・実行

use std::env;

fn powersign(n: i64) -> i64 {
    if n % 2 == 0 {
        1
    } else {
        -1
    }
}

fn leibniz(n: i64) -> f64 {
    let mut s: f64 = 0.0;
    for k in 0..=n {
        s += powersign(k) as f64/ (2 * k + 1) as f64;
    }
    4.0 * s
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let n = &args[1].parse::<i64>().unwrap();
    println!("{}", leibniz(*n));
}

コンパイル:

$ rustc -C opt-level=3 -o leibniz-rust leibniz.rs

実行:

$ time ./leibniz-rust 10000000000
3.141592653688346

________________________________________________________
Executed in   19.24 secs    fish           external
   usr time   18.36 secs    0.16 millis   18.36 secs
   sys time    0.04 secs    1.74 millis    0.04 secs

C++ での実装・コンパイル・実行

#include <cstdint>
#include <sstream>
#include <iostream>
#include <limits>

template <typename T>
auto is_even(T n) {
    return n % T{2} == T{0};
}

template <typename T>
auto powersign(T n) {
    return is_even(n) ? T{1} : T{-1};
}

template <typename T>
auto leibniz(T n) {
	using F = double;
    auto s = F{0};
    for (auto k = T{0}; k <= n; k++) {
        s += static_cast<F>(powersign(k)) / static_cast<F>(T{2} * k + T{1});
    }
    return F{4} * s;
}

int main(int, char * argv[]) {
    std::stringstream stream;
    stream << argv[1];
    int64_t n;
    stream >> n;

    typedef std::numeric_limits<double> lim;
    std::cout.precision(lim::max_digits10);
    std::cout << leibniz(n) << std::endl;
}

コンパイル:

$ clang++ -O3 -o leibniz-c++ leibniz.cpp

実行:

$ time ./leibniz-c++ 10000000000
3.1415926536883458

________________________________________________________
Executed in   11.50 secs    fish           external
   usr time   11.44 secs    0.11 millis   11.44 secs
   sys time    0.03 secs    1.02 millis    0.03 secs

考察

C++ で実装し Clang-15.0.7 でコンパイルしたものだと 11.44 秒かかるものが Rust/rustc-1.67.1 だと 18.36 秒もかかる。遅すぎる。

昔(数年前)、同様のコードで速度差をテストしたときは、差異はほとんどなかったはずなのに、なぜなのだろうか。コンパイラが悪くなってしまったのだろうか。なぜ Rust のコードが遅いのかわかる方がいらっしゃったら教えて下さい。

bannerAds