pub fn distance_fast(x: &[u8], y: &[u8]) -> Result<u64, DistanceError>
Expand description

Computes the bitwise Hamming distance between x and y, that is, the number of bits where x and y differ, or, the number of set bits in the xor of x and y.

This is a highly optimised version of the following naive version:

fn naive(x: &[u8], y: &[u8]) -> u64 {
    x.iter().zip(y).fold(0, |a, (b, c)| a + (*b ^ *c).count_ones() as u64)
}

This function requires that x and y have the same 8-byte alignment (that is, x.as_ptr() as usize % 8 == y.as_ptr() as usize % 8). If not, Err is returned. If sub-optimal performance can be tolerated, consider using distance which incorporates a fallback to a slower but less restrictive algorithm.

It is essentially guaranteed that x and y will have the same 8-byte alignment if they are both just Vec<u8>s of non-trivial length (e.g. larger than 8) as in the example below.

This is implemented using the same tree-merging approach as weight, see there for details.

Panics

x and y must have the same length, or else distance_fast panics.

Performance Comparison

lengthnaive (ns)distance_fast (ns)naive/distance_fast
1560.83
1044450.97
1004614730.97
1,0004,51039711
10,00046,7002,74017
100,00045,60020,40022
1,000,0004,590,000196,00023

Examples

let x = vec![0xFF; 1000];
let y = vec![0; 1000];
assert_eq!(hamming::distance_fast(&x, &y), Ok(8 * 1000));

// same alignment, but moderately complicated
assert_eq!(hamming::distance_fast(&x[1..1000 - 8], &y[8 + 1..]), Ok(8 * (1000 - 8 - 1)));

// differing alignments
assert!(hamming::distance_fast(&x[1..], &y[..999]).is_err());