昨日の継続ですが、素数計算のロジックを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