< 返回版块

lll1985911 发表于 2021-01-28 12:52

两段程序,功能都是求和,从1一直加到100亿; 笔记本(mbp)硬件配置: MacBook Pro (Retina, 13-inch, Early 2013) 2.6 GHz 双核Intel Core i5 8 GB 1600 MHz DDR3

Rust版本: rustc: 1.48.0 (7eac88abb 2020-11-16)

第一段:

fn main() {
    // 求和上限100亿
    let upper: i128 = 10000000000;
    let mut i: i128 = 1;
    let mut sum: i128 = 0;
    while i <= upper {
        sum += i;
        i += 1;
    }
    println!("1 + ... + {} = {}", upper, sum);
}

编译:

rustc -O main.rs

执行结果:

1 + ... + 10000000000 = 50000000005000000000

real	0m0.008s
user	0m0.002s
sys	0m0.004s

几乎瞬间就跑完了(试着修改了几次upper变量,在百亿数量级左右基本都是瞬间跑完)

##########################################分割线######################################

第二段:

第二段将上限变量(upper)改由命令行参数传入

use std::env;
fn main() {
    let args: Vec<String> = env::args().collect();
    let upper = &args[1];
    let upper = upper.parse::<i128>().unwrap();
    let mut i: i128 = 1;
    let mut sum: i128 = 0;
    while i <= upper {
        sum += i;
        i += 1;
    }
    println!("1 + ... + {} = {}", upper, sum);
}

编译:

rustc -O main.rs

执行结果:

1 + ... + 10000000000 = 50000000005000000000

real	0m11.161s
user	0m10.862s
sys	0m0.099s

用时约11秒(试了几次)

另:两段程序分别又随机测试了千亿数量级的几个数,第一段基本都是瞬间(秒级)跑 完,但第二段在千亿数量级上耗时基本都在2~3分钟级别。

不知何故?企盼解惑!

评论区

写评论
Mike Tang 2021-01-28 17:35

有一种计算叫查表法。

作者 lll1985911 2021-01-28 17:28

看了https://godbolt.org/z/xqMhen的汇编指令,确实是这样,第一段在编译阶段就算出来了(汇编指令里直接就有结果了),我奇怪的这么大的数字计算总是需要时间的吧?为啥编译就1、2秒就好,这么快?

--
👇
gwy15: 1. 第一个由于是常量,直接在编译期优化掉了运算过程 2. 对于这种简单的求和,编译器理论上应该直接优化掉的,但是 2.1 rustc 目前对 (..=) 实现有点问题,以下两种写法:

    let mut sum = 0;
    for i in 1..(upper+1) {
        sum += i;
    }
    sum

    let mut sum = 0;
    for i in 1..=upper {
        sum += i;
    }
    sum

第一种会优化成 x(x+1)/2,第二种不会。

见 https://godbolt.org/z/xqMhen

Aaron009 2021-01-28 14:48

--
👇
Mike Tang: 因为第一个字面量,编译器在编译的时候就帮你算完了,运行的时候直接打结果。

扩展可以看看 const generic.

哇撒。厉害,跟我想的一样。

gwy15 2021-01-28 13:30
  1. 第一个由于是常量,直接在编译期优化掉了运算过程
  2. 对于这种简单的求和,编译器理论上应该直接优化掉的,但是 2.1 rustc 目前对 (..=) 实现有点问题,以下两种写法:
    let mut sum = 0;
    for i in 1..(upper+1) {
        sum += i;
    }
    sum

    let mut sum = 0;
    for i in 1..=upper {
        sum += i;
    }
    sum

第一种会优化成 x(x+1)/2,第二种不会。

见 https://godbolt.org/z/xqMhen

Mike Tang 2021-01-28 13:09

因为第一个字面量,编译器在编译的时候就帮你算完了,运行的时候直接打结果。

扩展可以看看 const generic.

1 共 5 条评论, 1 页