Vectors
Rust provides portable SIMD vectors with the Simd
type.
Simd<T, N>
can be thought of as a variation of [T; N]
.
Simd
has the same “shape” as an array, but may have a greater alignment.
In fact, Simd<T, N>
is easily convertible to and from [T; N]
, and supports some of the same operations, such as indexing.
Elementwise operations on vectors
Unlike arrays, Simd<T, N>
is not just a container.
While it looks like an array, it also operates like T
.
Vectors implement all of the same basic operators as its scalar type T
, meaning you can do the following:
#![feature(portable_simd)] fn main() {} use std::simd::f32x4; // an alias for Simd<f32, 4> /// y = mx + b fn y(m: f32x4, x: f32x4, b: f32x4) -> f32x4 { m * x + b }
These operators work elementwise, meaning the operator is applied to each element separately.
Vectors even implement special functions (e.g. abs
) with traits:
#![feature(portable_simd)] fn main() {} use std::simd::{f32x4, SimdFloat}; // SimdFloat provides abs /// |a - b| fn distance(a: f32x4, b: f32x4) -> f32x4 { (a - b).abs() }
Reduction operations
Sometimes you may want to perform an operation across a single vector, rather than between vectors. These operations are referred to as reductions:
#![feature(portable_simd)] fn main() {} use std::simd::{f32x4, SimdFloat}; // SimdFloat provides reduce_sum fn sum(vectors: &[f32x4]) -> f32 { let mut sums = f32x4::splat(0.0); // splat fills each element with the value for v in vectors { sums += v; } // `sums` now contains the elementwise sums, so we must sum across the vector sums.reduce_sum() }