假设我们想快速找到数组中第一个非零元素的索引,效果如下
fn leading_zeros(arr: &[u32]) -> Option<usize> {
arr.iter().position(|&x| x != 0)
}
Run Code Online (Sandbox Code Playgroud)
但是,这会被编译为逐一检查,rustc如下所示。u128通过使用如下类型检查单词 4 by 4,可以稍微加快速度。这使我的机器的速度提高了大约 3 倍。
fn leading_zeros_wide(arr: &[u32]) -> Option<usize> {
let (beg, mid, _) = unsafe { arr.align_to::<u128>() };
beg.iter().position(|&x| x != 0).or_else(|| {
let left = beg.len() + 4 * mid.iter().position(|&x| x != 0).unwrap_or(mid.len());
arr[left..].iter().position(|&x| x != 0).map(|p| p + left)
})
}
Run Code Online (Sandbox Code Playgroud)
有没有办法让它更快?
这是我用来确定 3 倍加速的基准:
#![feature(test)]
extern crate test;
fn v() -> Box<[u32]> {
std::iter::repeat(0).take(1000).collect()
}
// Assume `leading_zeros` and `leading_zeros_wide` are defined here.
#[bench]
fn bench_leading_zeros(b: &mut test::Bencher) {
let v = test::black_box(v());
b.iter(|| leading_zeros(&v[3..]))
}
#[bench]
fn bench_leading_zeros_wide(b: &mut test::Bencher) {
let v = test::black_box(v());
b.iter(|| leading_zeros_wide(&v[3..]))
}
Run Code Online (Sandbox Code Playgroud)
这是一个解决方案,它比基线更快,但可能仍然有很多问题需要解决。
以下实现了基线的 7.5 倍first_nonzero。
/// Finds the position of the first nonzero element in a given slice which
/// contains a nonzero.
///
/// # Safety
///
/// The caller *has* to ensure that the input slice has a nonzero.
unsafe fn first_nonzero_padded(arr: &[u32]) -> usize {
let (beg, mid, _) = arr.align_to::<u128>();
beg.iter().position(|&x| x != 0).unwrap_or_else(|| {
let left = beg.len()
+ 4 * {
let mut p: *const u128 = mid.as_ptr();
loop {
if *p.offset(0) != 0 { break p.offset(0); }
if *p.offset(1) != 0 { break p.offset(1); }
if *p.offset(2) != 0 { break p.offset(2); }
if *p.offset(3) != 0 { break p.offset(3); }
if *p.offset(4) != 0 { break p.offset(4); }
if *p.offset(5) != 0 { break p.offset(5); }
if *p.offset(6) != 0 { break p.offset(6); }
if *p.offset(7) != 0 { break p.offset(7); }
p = p.offset(8);
}.offset_from(mid.as_ptr()) as usize
};
if let Some(p) = arr[left..].iter().position(|&x| x != 0) {
left + p
} else {
core::hint::unreachable_unchecked()
}
})
}
Run Code Online (Sandbox Code Playgroud)