hash算法Fnv-1a

hash算法fnv

  • FNV哈希算法 取自于1991年Glenn Fowler和 Phong Vo向IEEE POSIX P1003.2委员会发送评论者意见的想法 。在随后的投票中: Landon Curt Noll 对他们的算法进行了改进。一些人尝试了此哈希,发现它工作得很好。在发给 Landon的电子邮件中,他们将其命名为`` Fowler / Noll / Vo ''或FNV哈希

  • FNV哈希被设计为快速,同时保持较低的冲突率。该 FNV速度允许一个快速散列大量的数据,同时保持合理的碰撞率。FNV散列的高度分散性使其非常适合散列几乎相同的字符串,例如URL,主机名,文件名,文本,IP地址等

fnv版本

  • FNV
  • FNV-1
  • FNV-1a

FNV-1a 算法公式

hash = offset_basis
for each octet_of_data to be hashed
        hash = hash xor octet_of_data
        hash = hash * FNV_prime
return hash

其与FNV-1算法的区别就是异或运算与乘法运算顺序调整了,即是说FNV-1算法是先进行乘法运算再进行异或运算

参数说明

  1. offset_basis 参数依赖于hash位数的大小
  • 32 bit offset_basis = 2166136261

  • 64 bit offset_basis = 14695981039346656037

  • 128 bit offset_basis = 144066263297769815596495629667062367629

  • 256 bit offset_basis =
    100029257958052580907070968620625704837092796014241193945225284501741471925557

  • 512 bit offset_basis =
    9659303129496669498009435400716310466090418745672637896108374329434462657994582932197716438449813051892206539805784495328239340083876191928701583869517785

  • 1024 bit offset_basis =
    14197795064947621068722070641403218320880622795441933960878474914617582723252296732303717722150864096521202355549365628174669108571814760471015076148029755969804077320157692458563003215304957150157403644460363550505412711285966361610267868082893823963790439336411086884584107735010676915

  • offset_basis 计算脚本

hash_bits = insert_the_hash_size_in_bits_here;
FNV_prime = insert_the_FNV_prime_here;
offset_basis = 0;
offset_str = “chongo /\…/\”;
hash_mod = 2hash_bits;
str_len = strlen(offset_str);
for (i=1; i <= str_len; ++i) {
offset_basis = (offset_basis * FNV_prime) % hash_mod;
offset_basis = xor(offset_basis, ord(substr(offset_str,i,1)));
}
//输出
print hash_bits, “bit offset_basis =”, offset_basis;

  1. FNV_prime参数依赖于hash位数的大小
  • 32 bit FNV_prime = 224 + 28 + 0x93 = 16777619
  • 64 bit FNV_prime = 240 + 28 + 0xb3 = 1099511628211
  • 128 bit FNV_prime = 288 + 28 + 0x3b = 309485009821345068724781371
  • 256 bit FNV_prime = 2168 + 28 + 0x63 = 374144419156711147060143317175368453031918731002211
  • 512 bit FNV_prime = 2344 + 28 + 0x57 =
    35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852759
  • 1024 bit FNV_prime = 2680 + 28 + 0x8d =
    5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082573
  1. octet_of_data 8位元数据或者单个字节数据

伪代码实现

	/**
	 * 这里的值跟2166136261等价,因为int大小越界调整为16进制表示
	 */
	private final static int offset_basis_32 = 0x811c9dc5; 
	
	private final static int FNV_prime_32 = 16777619;
	/**
	 * 
	 * @param str
	 * @return
	 */
	public static int hash(String str) {
		char[] chrs = str.toCharArray();
		int hash = offset_basis_32;
		for(int i=0;i<chrs.length;i++) {
			 hash ^= chrs[i];
			 hash *= FNV_prime_32;//乘法运算更快一点
			//hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24); //将上面的乘法运算改为移位和运算
		}
		return Math.abs(hash);
	}
	
	/**
	 * 获取限定长度的hash
	 * 注意长度大小
	 * @param str 初始字符串
	 * @param len hash位数
	 * @return
	 */
	public static int hashOfLen(String str,int len) {
		int hash = hash(str);
		hash = (hash >> len) ^ ( hash & ( (1<<len)-1 ) );
		return hash;
	}
	
	/**
	 * 获取限定最大的值的hash
	 * @param str 初始字符串
	 * @param max hash最大值
	 * @return
	 */
	public static int hashOfMax(String str,int max) {
		int hash = hash(str) % (max+1);
		return hash;
	}

特别注意的地方。

  • 按照长度缩小。基准值应选择大于当前值最接近的位数,例如你需要16位的长度,选择32位,需要54位长度 选择64位
  • 同理按照大小缩小也一样。如果选择最大值为99999,则选择32位 因为232 > 99999,如果选择最大值为3000000000,则选择64位 因为264 > 3000000000
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值