生成A.I(Gemini)でコード生成(@Rust)

昨日の継続ですが、素数計算のロジックをGeminiで作成してみた

<環境>

M1 Macbook Air

————————————————————–

GeminiにRustである範囲の素数計算するコード出してといって、多少は手を入れてますが、ほぼ生成されたそのまま

use std::time::Instant;

fn is_prime(num: u64) -> bool {
    if num <= 1 {
        return false;
    }
    if num <= 3 {
        return true;
    }
    if num % 2 == 0 || num % 3 == 0 {
        return false;
    }

    let mut i = 5;
    while i * i <= num {
        if num % i == 0 || num % (i + 2) == 0 {
            return false;
        }
        i += 6;
    }

    true
}

fn find_primes(start: u64, end: u64) {
    let mut pri: Vec = Vec::new();
    let start_time = Instant::now();
    for num in start..=end {
        if is_prime(num) {
            pri.push(num);
        }
    }
    let end_time = Instant::now();
    println!("Elapsed time: {:?}", end_time.duration_since(start_time));
    println!("number of primes: {}", pri.len());
}

fn main() {
    let start = 2;
    let end = 1000_000;

    println!("{}から{}までの素数:", start, end);
    find_primes(start, end);
}

最初に気づいたことは① 素数検出ロジックは2, 3で割り算できずかつ6の倍数の±1で割り切れないことが『標準』だということ、確かに計算量はそれだけでほぼ三分の一になるよね

次に、それをマルチスレッド化、これも自動生成

use rayon::prelude::*;
use std::time::Instant;

fn is_prime(num: u64) -> bool {
    if num <= 1 {
        return false;
    }
    if num <= 3 {
        return true;
    }
    if num % 2 == 0 || num % 3 == 0 {
        return false;
    }

    let mut i = 5;
    while i * i <= num { if num % i == 0 || num % (i + 2) == 0 { return false; } i += 6; } true } fn find_primes_multithreaded(start: u64, end: u64) -> Vec {
    (start..=end)
        .into_par_iter()
        .filter(|num| is_prime(*num))
        .collect()
}

fn main() {
    let start = 2;
    let end = 1000_000;

    println!("{}から{}までの素数:", start, end);

    let start_time = Instant::now();
    let primes = find_primes_multithreaded(start, end);
    let end_time = Instant::now();

    println!("Elapsed time: {:?}", end_time.duration_since(start_time));
    println!("number of primes: {}", primes.len());
}

② rayonとinto_par_iter()使えば、マルチスレッド化がプロセッサの数に応じて自動でiter処理を実行してくれること

ちなみに実行時間を測ってみると、

<Geminiで生成したシングルスレッド版 : release mode>
2から1000000までの素数:
Elapsed time: 37.51125ms


rayon::tierクレートのinto_par_iter()メソッドでマルチスレッド対応のiteratorが作れるということ、

<Geminiで生成したマルチスレッド版 : release mode>
2から1000000までの素数:
Elapsed time: 7.397958ms

昨日のロジックではrelease modeのバイナリで90ms程度要していたから、やはり三分の一程度高速化されていて、さらにマルチスレッド版(8CPU)でオーバーヘッドあるにしてもさらに5倍ぐらい高速化

というわけで、仕様を明確に定義できる領域であれば、生成A.I使った方が人が記述するより時間短縮して効率の良いコードが作成できるだろうということで、githubのcopilotなどのその範疇(使ったことはないけど)でしょう

逆に他の言語からのそのまま置き換え(変換)は元のコードがスマートでないと無駄な作業が発生するし、もしかしたらそれほど向いていないかもしれない

 

admin

カテゴリーRust