Horizontal ops
- Rust course
- Expert
- Lesson 22/46
- 4 min
Use horizontal operations like horizontal_reduce.
Horizontal operations
Lane-wise operations are "vertical" (lane i with lane i). Operations combining a vector's own lanes are "horizontal": reduce_sum, reduce_max, reduce_and. Horizontal operations are expensive, so they're done once at the end of the loop:
// nightly std::simd
let v = f32x8::from_array([1., 2., 3., 4., 5., 6., 7., 8.]);
let t = v.reduce_sum(); // 36
let m = v.reduce_max(); // 8Hardware usually does this as a "tree": first it adds the halves, then the quarters, until a single value remains.
Tree reduction
Summing by folding the lanes in half shows how horizontal reduction works:
fn yatay_toplam(v: [f32; 8]) -> f32 {
let d4: [f32; 4] = std::array::from_fn(|i| v[i] + v[i + 4]);
let d2: [f32; 2] = std::array::from_fn(|i| d4[i] + d4[i + 2]);
d2[0] + d2[1]
}At each step half of the array is added lane-wise to the other half; 8 → 4 → 2 → 1.
Practice Horizontal sum
Write the yatay_toplam function above. For [1.0, 2.0, ..., 8.0], print the result and the largest lane found with fold(f32::MIN, f32::max), separated by a space.
Starter code
fn main() {
// buraya yaz
}Sample solution
fn yatay_toplam(v: [f32; 8]) -> f32 {
let d4: [f32; 4] = std::array::from_fn(|i| v[i] + v[i + 4]);
let d2: [f32; 2] = std::array::from_fn(|i| d4[i] + d4[i + 2]);
d2[0] + d2[1]
}
fn main() {
let v = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let m = v.iter().copied().fold(f32::MIN, f32::max);
println!("{} {}", yatay_toplam(v), m);
}Expected output
36 8
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Does tree-shaped summation give the same result as left-to-right summation (f32)?
- Different only for integers
- Not always; floating-point addition isn't associative, small differences can occur Correct answer
- Always the same
- Never
Explanation: That's why the compiler doesn't reorder f32 sum loops by itself; explicit permission (or manual multiple accumulators) is needed.
2 Fold in half
let d4: [f32; 4] = std::array::from_fn(|i| v[i] + v[i + ____]);
let d4: [f32; 4] = std::array::from_fn(|i| v[i] + v[i + 4]);
Explanation: An 8-lane array goes down to 4 lanes by adding i and i + 4.
3 Operation and direction
| Term | Meaning |
|---|---|
a + b |
Vertical |
reduce_sum |
Horizontal |
reduce_max |
Horizontal (max) |
splat |
Broadcast |