I'm trying to use snrm2 to perform a single precision float calculation in Rust. I'm linking to the Accelerate framework on OSX and using the blas crate for the C-bridge. Regardless of the randomly generated vector values (which usually calculate to [12, 13] in the native code) the snrm2 logic consistently returns:
- -36893490000000000000
- -2
- 36893490000000000000
- 0
This same code works as advertised when I switch everything to f64 and dnrm2. Is this a bug within Accelerate, or am I not meeting some of its internal assumptions about memory alignment or call arguments?
use rand::prelude::*;
use blas::*;
type Vector = [f32; 2048];
// Native implementation
fn euclidean_distance_standard(a: &Vector, b: &Vector) -> f32 {
a.iter().zip(b.iter()).fold(0.0, |acc, (&x, &y)| {
let diff = x - y;
acc + diff * diff
}).sqrt()
}
// Using snrm2 from BLAS
fn euclidean_distance_blas(a: &Vector, b: &Vector) -> f32 {
let mut diff = [0.0; 2048];
for i in 0..2048 {
diff[i] = a[i] - b[i];
}
unsafe {
snrm2(diff.len() as i32, &diff, 1)
}
}
fn main() {
let mut rng = rand::thread_rng();
// Initialize a random vector
let mut vector_a = [0.0; 2048];
for i in 0..2048 {
vector_a[i] = rng.gen::<f32>();
}
let vector_b = [0.5; 2048];
let result_standard = euclidean_distance_standard(&vector_a, &vector_b);
let result_blas = euclidean_distance_blas(&vector_a, &vector_b);
println!("Standard Method Result: {}", result_standard);
println!("OpenBLAS Method Result: {}", result_blas);
}
# build.rs
fn main() {
println!("cargo:rustc-link-lib=framework=Accelerate");
}
# Cargo.toml
[dependencies]
rand = "0.8"
blas = "0.21"
blas-src = { version = "0.9", features = ["accelerate"] }
libc = "0.2.36"
$ cargo run --release
Finished release [optimized] target(s) in 0.01s
Running `target/release/similarity-comp`
Standard Method Result: 13.005363
OpenBLAS Method Result: -36893490000000000000