Код наивный:
use std::time;
fn main() {
const NUM_LOOP: u64 = std::u64::MAX;
let mut sum = 0u64;
let now = time::Instant::now();
for i in 0..NUM_LOOP {
sum += i;
}
let d = now.elapsed();
println!("{}", sum);
println!("loop: {}.{:09}s", d.as_secs(), d.subsec_nanos());
}
Вывод:
$ ./test.rs.out
9223372036854775809
loop: 0.000000060s
$ ./test.rs.out
9223372036854775809
loop: 0.000000052s
$ ./test.rs.out
9223372036854775809
loop: 0.000000045s
$ ./test.rs.out
9223372036854775809
loop: 0.000000041s
$ ./test.rs.out
9223372036854775809
loop: 0.000000046s
$ ./test.rs.out
9223372036854775809
loop: 0.000000047s
$ ./test.rs.out
9223372036854775809
loop: 0.000000045s
Программа почти сразу заканчивается.Я также написал эквивалентный код на языке C, используя цикл for, но он работал долго.Мне интересно, что делает код Rust таким быстрым.
Код C:
#include <stdint.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
double time_elapse(struct timespec start) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec - start.tv_sec +
(now.tv_nsec - start.tv_nsec) / 1000000000.;
}
int main() {
const uint64_t NUM_LOOP = 18446744073709551615u;
uint64_t sum = 0;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
for (int i = 0; i < NUM_LOOP; ++i) {
sum += i;
}
double t = time_elapse(now);
printf("value of sum is: %llu\n", sum);
printf("time elapse is: %lf sec\n", t);
return 0;
}
Код Rust компилируется с использованием -O
, а код C компилируется с использованием -O3
,Код C работает так медленно, что он еще не остановился.
После исправления ошибки, обнаруженной visibleman и Sandeep, обе программы печатали одно и то же число практически мгновенно.Я пытался уменьшить NUM_LOOP
на один, результаты казались разумными, учитывая переполнение.Более того, с NUM_LOOP = 1000000000
обе программы не будут переполнены и выдают правильные ответы в кратчайшие сроки.Какие оптимизации используются здесь?Я знаю, что мы можем использовать простые уравнения, такие как (0 + NUM_LOOP - 1) * NUM_LOOP / 2
, для вычисления результата, но я не думаю, что такие вычисления выполняются компиляторами в случае переполнения ...