功能说明
海明距离衡量两个等长序列在多少个位置上不同。按字节切片计算时,先逐字节异或,再统计结果中 1 的位数,因此得到的是比特级差异,适合校验码、感知哈希和近似重复检测。示例还提供相似度换算和长度校验。
对等长二进制数据,海明距离比逐字节比较更细:两个字节只差一位时,字节比较会认为完全不同,而海明距离只记一分,能反映损坏的严重程度。
关键代码
hamming_distance 先比较长度,不同长度返回错误,因为海明距离只对等长序列有定义。迭代 zip 后用异或合并每一对字节,count_ones 统计置位数,sum 累加得到总距离。hamming_distance_bits 对两个 u64 直接异或计数。similarity 拒绝空切片,再用一减去距离除以总位数,得到零到一之间的比例。
使用注意
长度不同必须先补齐或改用编辑距离,不能截断后比较,否则结果没有意义。按字节计算时比特序不影响总数,但跨语言传输要保证字节内容一致。海明距离不能反映换位,适合定长标识而不是自然语言。大文件应分块累计,避免一次性加载。相似度为零表示每个比特都不同,并不表示内容无关。
验证方式
karolin 与 kathrin 有三个字节不同,对应异或结果共有九位为一,距离输出为九。总位数为五十六,相似度约为 0.8393。两个 u64 的示例 1011 与 1001 只有一位不同,输出一。长度不一致的输入返回错误,打印为 true;空切片在相似度函数中同样被拒绝。
代码示例
fn hamming_distance(left: &[u8], right: &[u8]) -> Result<u32, String> {
if left.len() != right.len() {
return Err(format!(
"inputs must match in length: {} vs {}",
left.len(),
right.len()
));
}
Ok(left
.iter()
.zip(right.iter())
.map(|(a, b)| (a ^ b).count_ones())
.sum())
}
fn hamming_distance_bits(left: u64, right: u64) -> u32 {
(left ^ right).count_ones()
}
fn similarity(left: &[u8], right: &[u8]) -> Result<f64, String> {
if left.is_empty() {
return Err("inputs must not be empty".to_string());
}
let distance = hamming_distance(left, right)?;
let total_bits = (left.len() * 8) as f64;
Ok(1.0 - f64::from(distance) / total_bits)
}
fn main() {
let left = b"karolin";
let right = b"kathrin";
println!("distance: {:?}", hamming_distance(left, right));
println!("similarity: {:.4}", similarity(left, right).unwrap_or(0.0));
println!("bits: {}", hamming_distance_bits(0b1011, 0b1001));
println!("length mismatch: {}", hamming_distance(b"abc", b"ab").is_err());
}