JavaScript根据实数和整数计算哈希代码

JavaScript calculate hashcode from real number and integer number

本文关键字:计算 哈希 代码 整数 实数 JavaScript      更新时间:2023-09-26

嗨,我需要一个函数来从数字(实数双精度)和整数计算唯一的整数。

试着解释一下,我正在用javascript开发GIS应用程序,我正在处理复杂的矢量对象,如多边形(环中有两个坐标的点对象阵列)和点的线阵列。我需要快速的算法来识别元素已经改变——它必须非常快,因为我的向量对象是千点的集合。在C#中,我使用按位运算XOR从坐标计算哈希代码。

但是javascript将按位运算中的所有操作数转换为整数,但在以c(binary)方式按位应用之前,我需要将双精度转换为整数。在reflector中,我看到c#像这样计算双重哈希代码,我需要在javascript中尽可能快地使用这个函数。

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)));
}

示例:

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

示例结果不正确hash==hash1

示例2:使用字符串有正确的结果,但从字符串计算哈希是复杂的,我的事情不够快。

    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

示例2的结果是正确的哈希!=hash1

有没有比将数字转换为字符串比根据每个字符计算哈希更快的方法?因为我的物体很大,这样做需要很多时间和操作。。。

我试着用TypedArrays来做,但是我没有成功。

非常感谢您的帮助

嗨,我尝试使用TypedArrays从数字计算哈希代码,结果很有趣。在IE中,性能在Chrome中提高了4倍,在FireFox中提高了2倍,这种方法相当于字符串版本。。。

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;
     }

我认为这对来说很有用

编辑:使用一个缓冲区和DataView更快!

这里有一种在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];
}

它比DataView方法快250倍:请参阅基准测试。

我查找了一些哈希库,看看它们是如何做到的:xxhashjs、jshashes等。

大多数似乎采用字符串或ArrayBuffer,并且还依赖于类似UINT32的功能。这相当于您需要一个双精度的二进制表示(来自C#示例)。值得注意的是,除了在另一个(未回答的)问题中,我没有找到任何包含更多奇怪类型的解决方案。

他的解决方案使用了这里提出的方法,该方法将其转换为各种类型的数组。这很可能是您想要的,也是最快、准确的解决方案(我认为)。

我强烈建议您根据需要构建代码以遍历对象/数组,并对解决方案进行基准测试,看看它与现有方法(非工作方法和字符串方法)的可比性。