liurunyu
3 天以前 7f85ca5468e097f1749ab1ed812046cb8eb979b7
pipIrr-platform/pipIrr-common/src/main/java/com/dy/common/util/MurmurHash.java
New file
@@ -0,0 +1,302 @@
package com.dy.common.util;
/**
 * MurmurHash算法:高运算性能,低碰撞率,由Austin Appleby创建于2008年,
 * 现已应用到Hadoop、libstdc++、nginx、libmemcached等开源系统。2011年
 * Appleby被Google雇佣,随后Google推出其变种的CityHash算法。
 *
 * 官方网站:https://sites.google.com/site/murmurhash/
 *
 * MurmurHash算法,自称超级快的hash算法,是FNV的4-5倍。官方数据如下:
 *
 * OneAtATime – 354.163715 mb/sec
 * FNV – 443.668038 mb/sec
 * SuperFastHash – 985.335173 mb/sec
 * lookup3 – 988.080652 mb/sec
 * MurmurHash 1.0 – 1363.293480 mb/sec
 * MurmurHash 2.0 – 2056.885653 mb/sec
 *
 * 但也有文章声称,只有当key的长度大于10字节的时候,MurmurHash的运算速
 * 度才快于DJB。从计算速度上来看,MurmurHash只适用于已知长度的、长度比
 * 较长的字符。
 *
 * 哈希值分布非常均匀,即低碰撞率
 * 比Crc16更为均匀
 */
public final class MurmurHash {
    private byte[] toBytesWithoutEncoding(String str) {
        int len = str.length();
        int pos = 0;
        byte[] buf = new byte[len << 1];
        for (int i = 0; i < len; i++) {
            char c = str.charAt(i);
            buf[pos++] = (byte) (c & 0xFF);
            buf[pos++] = (byte) (c >> 8);
        }
        return buf;
    }
    /**
     * 刘润玉增加方法于2016-12-02
     * @param data
     * @param length
     * @return
     */
    public int hash16_plus(final byte[] data, int length) {
        int hash = hash32(data, length, 0x9747b28c);
        hash = hash % 65535 ;
        if(hash < 0){
           hash = - hash ;
        }
        return hash ;
    }
    /**
     * 刘润玉增加方法于2016-12-02
     * @param data
     * @return
     */
    public int hash16_plus(final String data) {
        byte[] bytes = toBytesWithoutEncoding(data);
        int hash = hash32(bytes, bytes.length, 0x9747b28c);
        hash = hash % 65535 ;
        if(hash < 0){
           hash = - hash ;
        }
        return hash ;
    }
    /**
     * Generates 32 bit hash from byte array with default seed value.
     * @param  data byte array to hash
     * @param length length of the array to hash
     * @return 32 bit hash of the given array
     */
    public int hash32(final byte[] data, int length) {
        return hash32(data, length, 0x9747b28c);
    }
    public int hash32(final String data) {
        byte[] bytes = toBytesWithoutEncoding(data);
        return hash32(bytes, bytes.length, 0x9747b28c);
    }
    /**
     * Generates 64 bit hash from byte array with default seed value.
     * @param  data byte array to hash
     * @param length length of the array to hash
     * @return  64 bit hash of the given string
     */
    public long hash64(final byte[] data, int length) {
        return hash64(data, length, 0xe17a1465);
    }
    public long hash64(final String data) {
        byte[] bytes = toBytesWithoutEncoding(data);
        return hash64(bytes, bytes.length);
    }
    /**
     * Generates 32 bit hash from byte array of the given length and seed.
     * @param data byte array to hash
    * @param length length of the array
    * @param seed initial seed value
    * @return 32 bit hash of the given array
     */
    public int hash32(final byte[] data, int length, int seed) {
        // 'm' and 'r' are mixing constants generated offline.
        // They're not really 'magic', they just happen to work well.
        final int m = 0x5bd1e995;
        final int r = 24;
        // Initialize the hash to a random value
        int h = seed ^ length;
        int length4 = length / 4;
        for (int i = 0; i < length4; i++) {
            final int i4 = i * 4;
            int k = (data[i4 + 0] & 0xff) + ((data[i4 + 1] & 0xff) << 8)
                    + ((data[i4 + 2] & 0xff) << 16)
                    + ((data[i4 + 3] & 0xff) << 24);
            k *= m;
            k ^= k >>> r;
            k *= m;
            h *= m;
            h ^= k;
        }
        // Handle the last few bytes of the input array
        switch (length % 4) {
        case 3:
            h ^= (data[(length & ~3) + 2] & 0xff) << 16;
        case 2:
            h ^= (data[(length & ~3) + 1] & 0xff) << 8;
        case 1:
            h ^= (data[length & ~3] & 0xff);
            h *= m;
        }
        h ^= h >>> 13;
        h *= m;
        h ^= h >>> 15;
        return h;
    }
    /**
     * Generates 64 bit hash from byte array of the given length and seed.
     * @param data byte array to hash
     * @param length length of the array to hash
     * @param seed initial seed value
     * @return 64 bit hash of the given array
     */
    public long hash64(final byte[] data, int length, int seed) {
        final long m = 0xc6a4a7935bd1e995L;
        final int r = 47;
        long h = (seed & 0xffffffffl) ^ (length * m);
        int length8 = length / 8;
        for (int i = 0; i < length8; i++) {
            final int i8 = i * 8;
            long k = ((long) data[i8 + 0] & 0xff)
                    + (((long) data[i8 + 1] & 0xff) << 8)
                    + (((long) data[i8 + 2] & 0xff) << 16)
                    + (((long) data[i8 + 3] & 0xff) << 24)
                    + (((long) data[i8 + 4] & 0xff) << 32)
                    + (((long) data[i8 + 5] & 0xff) << 40)
                    + (((long) data[i8 + 6] & 0xff) << 48)
                    + (((long) data[i8 + 7] & 0xff) << 56);
            k *= m;
            k ^= k >>> r;
            k *= m;
            h ^= k;
            h *= m;
        }
        switch (length % 8) {
        case 7:
            h ^= (long) (data[(length & ~7) + 6] & 0xff) << 48;
        case 6:
            h ^= (long) (data[(length & ~7) + 5] & 0xff) << 40;
        case 5:
            h ^= (long) (data[(length & ~7) + 4] & 0xff) << 32;
        case 4:
            h ^= (long) (data[(length & ~7) + 3] & 0xff) << 24;
        case 3:
            h ^= (long) (data[(length & ~7) + 2] & 0xff) << 16;
        case 2:
            h ^= (long) (data[(length & ~7) + 1] & 0xff) << 8;
        case 1:
            h ^= (long) (data[length & ~7] & 0xff);
            h *= m;
        }
        ;
        h ^= h >>> r;
        h *= m;
        h ^= h >>> r;
        return h;
    }
    public static void main(String[] args) {
       test1() ;
       test2() ;
    }
    public static void test1() {
       String regionNum = "110000" ;
      String temp = "" ;
      String rtuAddr = "" ;
      int total0 = 0 ;
      int total1 = 0 ;
      int total2 = 0 ;
      int total3 = 0 ;
      int total4 = 0 ;
      int total5 = 0 ;
      int totalx = 0 ;
      int totaly = 0 ;
      MurmurHash mhash = new MurmurHash() ;
      Long start = System.currentTimeMillis() ;
      for(int i = 0 ; i < 10000; i++){
         temp = "" + i ;
         while(temp.length() < 5){
            temp = "0" + temp ;
         }
         rtuAddr = regionNum + temp ;
         int hash = mhash.hash16_plus(rtuAddr) ;
         if(hash < 0){
            total0++ ;
         }
         if(hash >= 0 && hash < 1000){
            total1++ ;
         }
         if(hash >= 1000 && hash < 2000){
            total2++ ;
         }
         if(hash >= 2000 && hash < 3000){
            total3++ ;
         }
         if(hash >= 3000 && hash < 4000){
            total4++ ;
         }
         if(hash >= 4000 && hash < 5000){
            total5++ ;
         }
         if(hash >= 64535 && hash < 65535){
            totalx++ ;
         }
         if(hash > 65535){
            totaly++ ;
         }
         //System.out.println(rtuAddr + "-" + crc);
      }
      Long end = System.currentTimeMillis() ;
      System.out.println("用时" + ":" + (end - start));
      System.out.println("0以下" + ":" + total0);
      System.out.println("0-1000" + ":" + total1);
      System.out.println("1000-2000" + ":" + total2);
      System.out.println("2000-3000" + ":" + total3);
      System.out.println("3000-4000" + ":" + total4);
      System.out.println("5000-6000" + ":" + total5);
      System.out.println("64535-65535" + ":" + totalx);
      System.out.println("65535以上" + ":" + totaly);
      System.out.println("=================");
   }
   public static void test2() {
      String regionNum = "110000" ;
      String temp = "" ;
      String rtuAddr = "" ;
      int total1 = 0 ;
      int total2 = 0 ;
      int total3 = 0 ;
      int total4 = 0 ;
      int total5 = 0 ;
      MurmurHash mhash = new MurmurHash() ;
      Long start = System.currentTimeMillis() ;
      for(int i = 0 ; i < 10000; i++){
         temp = "" ;
         temp = "" + i ;
         while(temp.length() < 5){
            temp = "0" + temp ;
         }
         rtuAddr = regionNum + temp ;
         int hash = mhash.hash32(rtuAddr) ;
         if(hash > 0 && hash < 10000000){
            total1++ ;
         }
         if(hash >= 10000000 && hash < 20000000){
            total2++ ;
         }
         if(hash >= 20000000 && hash < 30000000){
            total3++ ;
         }
         if(hash >= 30000000 && hash < 40000000){
            total4++ ;
         }
         if(hash >= 40000000 && hash < 50000000){
            total5++ ;
         }
         //System.out.println(rtuAddr + "-" + crc);
      }
      Long end = System.currentTimeMillis() ;
      System.out.println("用时" + ":" + (end - start));
      System.out.println("0-10000000" + ":" + total1);
      System.out.println("10000000-20000000" + ":" + total2);
      System.out.println("20000000-30000000" + ":" + total3);
      System.out.println("30000000-40000000" + ":" + total4);
      System.out.println("50000000-60000000" + ":" + total5);
      System.out.println("=================");
   }
}