< 返回版块

Neutron3529 发表于 2023-04-15 19:19

闲来无事,准备熟悉一下fft大数乘法,写一个快速计算fibonacci数列的rust小程序

然后……

self.f1.iter_mut()
    .zip(self.f5.iter().zip(self.bf.iter()))
    .take(self.len)
    .for_each(|(r,(s,t))|
        *r=*r**r+5.**s**s+2.**t // 这里出现了,python中的乘方算符`**`🤣
    );

这样的代码写起来并不复杂,但我仍然有一些疑惑

首先,我能信任Rust的优化吗? 或者说,Rust会把这种到处iter然后解引用的算法改成SIMD指令吗? 如果开Rayon再次加速呢?

其次,我想知道,Rust一般是如何处理iter的语法 我知道有一些解引用的写法,比如for_each(|(r,(&s,&t))|*r=*r**r+5.*s*s+2.*t)可以去掉不少乘方算符(嗯,**🤣),但*r是消不掉的,.pow(2)大概可以消掉乘方算符,但我可以相信rust的优化能力,相信Rust一定能把r.pow(2)优化成r*r吗?

有时候我习惯于写.into_iter()而不是.iter(),有这个必要吗?

最后,这里到底应该使用迭代器,还是for循环呢? 使用for循环会不会带来额外的边界检查开销呢? 这里zip里面套zip会不会让编译器感到为难呢?


fft计算fibonacci的代码还在写,写完了我发上来。 写这个帖子主要是因为……不小心写出乘方算符实在有些搞笑

评论区

写评论
viruscamp 2023-04-16 00:45
.for_each(|(r,(s,t))| 
    *r = {
        let r = *r; // 对 r: &mut f64 如果用的很多,或者解引用让你不舒服,可以这样做
        r * r + 5.0 * s * s + 2.0 * t // 对 s: &f64, t: &f64 之类的计算,不必解引用
    }
);
viruscamp 2023-04-16 00:30
  1. 通常会内联展开成 for 循环, 然后让 llvm 优化成 simd
  2. rayon 没有直接支持 simd, 较小集合与较少的计算用 rayon 大概会破坏循环展开,反而降低性能
  3. 以后不用的集合用 into_iter() 还有用的用 iter() 或者 iter_mut()
ThalliMega 2023-04-15 19:52
for (r,(s,t)) in self.f1.iter_mut()
    .zip(self.f5.iter().copied().zip(self.bf.iter().copied()))
    .take(self.len) {
    let v = *r;
    *r=v*v+5.*s*s+2.*t;
}
1 共 3 条评论, 1 页