2015-07-01 24 views
5

Ciao, ho bisogno di una funzione per calcolare un numero intero univoco dal numero (numero reale doppia precisione) e numero intero.JavaScript calcola hashcode dal numero reale e dal numero intero

Prova a spiegare Sto sviluppando un'applicazione GIS in javascript e sto lavorando con oggetti vettoriali complessi come poligono (array di punti oggetto con due coordinate nell'anello) e linee di punti. Ho bisogno di un algoritmo veloce per riconoscere che l'elemento è stato cambiato deve essere molto veloce perché il mio oggetto vettoriale è una raccolta di migliaia di punti. In C# sto calcolando il codice hash dalla coordinata utilizzando l'operazione bit a bit XOR.

Ma javascript converte tutti gli operandi in operazioni bit a bit in numero intero ma ho bisogno di convertire la precisione doppia in numero intero prima di applicarlo a bit in modo C# (binnary). Nel reflector vedo questo che C# calcola il codice hash da double come questo e ho bisogno di questa funzione in javascript il più velocemente possibile.

public override unsafe int GetHashCode() //from System.Double 
{ 
    double num = this; 
    if (num == 0.0) 
    { 
     return 0; 
    } 
    long num2 = *((long*) &num); 
    return (((int) num2)^((int) (num2 >> 32))); 
} 

Esempio:

var rotation = function (n) { 
    n = (n >> 1) | ((n & 0x001) << 31); 
    return n; 
} 

var x: number = 1; 
var y: number = 5; 

var hash = x^rotation(y); // result is -2147483645 

var x1: number = 1.1; 
var y1: number = 5; 

var hash1 = x1^rotation(y1); // result is -2147483645 

Esempio risultato non è corretto hash == hash1

Esempio 2: utilizzo di stringa non è corretto risultato, ma calcolare Hash da stringa è quello di complicare e io cosa non è abbastanza veloce

var rotation = function (n) { 
     n = (n >> 1) | ((n & 0x001) << 31); 
     return n; 
    } 

    var GetHashCodeString = function(str: string): number { 
     var hash = 0, i, l, ch; 
     if (str.length == 0) return hash; 
     for (i = 0, l = str.length; i < l; i++) { 
      ch = str.charCodeAt(i); 
      hash = ((hash << 5) - hash) + ch; 
      hash |= 0; // Convert to 32bit integer 
     } 
     return hash; 
    } 

    var x: number = 1; 
    var y: number = 5; 

    var hash = GetHashCodeString(x.toString())^rotation(GetHashCodeString(y.toString())); 
    //result is -2147483605 
    var x1: number = 1.1; 
    var y1: number = 5; 

    var hash1 = GetHashCodeString(x1.toString())^rotation(GetHashCodeString(y1.toString())); 
    //result is -2147435090 

risultato Example2 è corretto hash! = Hash1

C'è qualche modo più veloce di convertire il numero a stringa di calcolo hash da ogni personaggio? Perché il mio oggetto è molto grande e ci vorrà molto tempo e operazioni in questo modo ...

Io provo a farlo usando TypedArrays ma ancora non ho successo.

Grazie mille per il vostro aiuto

risposta

1

Ecco un modo più veloce per farlo in JavaScript.

const kBuf = new ArrayBuffer(8); 
const kBufAsF64 = new Float64Array(kBuf); 
const kBufAsI32 = new Int32Array(kBuf); 

function hashNumber(n) { 
    // Remove this `if` if you want 0 and -0 to hash to different values. 
    if (~~n === n) { 
    return ~~n; 
    } 
    kBufAsF64[0] = n; 
    return kBufAsI32[0]^kBufAsI32[1]; 
} 

E '250x più veloce rispetto all'approccio DataView: see benchmark.

1

ho guardato alcune librerie di hashing per vedere come hanno fatto: xxhashjs, jshashes, ecc

La maggior parte sembrano prendere una stringa o un ArrayBuffer, e anche dipendono su funzionalità tipo UINT32. Questo equivale a te che hai bisogno di una rappresentazione binaria del doppio (dal tuo esempio C#). In particolare, non ho trovato nessuna soluzione che includesse tipi più strani, tranne che in un'altra (senza risposta) question.

La sua soluzione utilizza un metodo proposto here, che lo converte in vari array tipizzati. Questo è probabilmente quello che vuoi e la soluzione più rapida e precisa (credo).

Consiglio vivamente di strutturare il codice per attraversare oggetti/matrici come desiderato e anche di confrontare la soluzione per vedere quanto è paragonabile ai metodi esistenti (quello non funzionante e quello di stringa).

+0

Ciao, grazie mille l'ho risolto io stesso pochi minuti prima del tuo post ... ma grazie mille ... –

+0

Non posso commentare la tua risposta, mi dispiace. La tua soluzione utilizza più chiamate rispetto a quella a cui mi sono collegato, quindi mi aspetto che questa sarà più veloce. Si prega di verificare e quindi accettare la risposta più veloce. – Neofish

+1

vedo che non usano dataview ... ci proverò! Grazie –

2

Ciao, ho provato a usare TypedArrays per calcolare il codice hash dal numero e il risultato è interessante. In IE il 4x migliore performance in Chrome 2x in FireFox questo approccio è uguale alla versione stringa ...

var GetHashCodeNumber = function (n: number): number { 
     //create 8 byte array buffer number in js is 64bit 
     var arr = new ArrayBuffer(8); 

     //create view to array buffer 
     var dv = new DataView(arr); 

     //set number to buffer as 64 bit float 
     dv.setFloat64(0, n); 

     //now get first 32 bit from array and convert it to integer 
     // from offset 0 
     var c = dv.getInt32(0); 

     //now get next 32 bit from array and convert it to integer 
     //from offset 4 
     var d = dv.getInt32(4); 

     //XOR first end second integer numbers 
     return c^d; 
    } 

Penso che questo può essere utile per qualcuno

EDIT: utilizzando uno buffer e DataView è più veloce!

Problemi correlati