CodeBlanks Logo Icon CodeBlanks

Horizontal ops

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();   // 8

Hardware 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

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
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

Question
let d4: [f32; 4] = std::array::from_fn(|i| v[i] + v[i + ____]);
Answer
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

All lessons in Expert