← 中文资源

简体中文版本

字节序列海明距离

统计等长字节序列之间不同的比特数,换算相似度,并拒绝长度不一致或为空的输入。

阅读英文原文

功能说明

海明距离衡量两个等长序列在多少个位置上不同。按字节切片计算时,先逐字节异或,再统计结果中 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());
}