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("================="); 
 | 
    } 
 | 
}   
 |