【问题标题】:Using a float in Javascript in a hash function在散列函数中使用 Javascript 中的浮点数
【发布时间】:2019-11-29 08:59:28
【问题描述】:

我有一个这样的哈希函数。

class Hash {
  static rotate (x, b) {
    return (x << b) ^ (x >> (32-b));
  }
  static pcg (a) {
    let b = a;
    for (let i = 0; i < 3; i++) {
      a = Hash.rotate((a^0xcafebabe) + (b^0xfaceb00c), 23);
      b = Hash.rotate((a^0xdeadbeef) + (b^0x8badf00d), 5);
    }
    return a^b;
  }
}
// source Adam Smith: https://groups.google.com/forum/#!msg/proceduralcontent/AuvxuA1xqmE/T8t88r2rfUcJ

我就是这样用的。

console.log(Hash.pcg(116)); // Output: -191955715

只要我发送一个整数,我就会得到一个整数。现在问题来了。如果我有一个浮点数作为输入,则会发生舍入。数字 Hash.pcg(1.1) 和 Hash.pcg(1.2) 将产生相同的结果。我希望不同的输入产生不同的结果。一种可能的解决方案是将输入相乘,这样小数点就不会向下舍入,但是有没有更优雅和灵活的解决方案?

有没有办法将浮点数转换为唯一整数?每个浮点数都会产生不同的整数。

性能很重要。

【问题讨论】:

  • BigInt 类型变得广泛可用时,您将能够将其用于所有按位运算。

标签: javascript floating-point type-conversion integer hash-function


【解决方案1】:

这不是一个完整的答案,但我没有足够的空间来发表评论。 :)

您会遇到 32 位范围之外的整数以及非整数值的问题。

JavaScript 将所有数字处理为 64 位浮点数。这会为您提供 -9007199254740991 到 9007199254740991 (±(2^53 - 1)) 范围内的精确整数,但哈希算法中使用的按位运算符(^&lt;&lt;&gt;&gt;)仅适用于32 位范围。

由于可能的非整数比整数多得多,因此不可能与普通数进行一对一的映射。您可以使用 BigInts 解决问题,但这可能会导致性能相对较慢。

如果您愿意处理性能问题,可以使用 JavaScript 缓冲区函数来获取浮点数的实际位。 (我现在会说更多关于如何做到这一点,但我必须跑!)

编辑...吃完饭回来...

您可以将 JavaScript 的标准 number 类型(64 位浮点)转换为 BigInt,如下所示:

let dv = new DataView(new ArrayBuffer(8));
dv.setFloat64(0, Math.PI);
console.log(dv.getFloat64(0), dv.getBigInt64(0), dv.getBigInt64(0).toString(16).toUpperCase())

由此产生的输出是:

3.141592653589793 4614256656552045848n "400921FB54442D18"

第一项显示该数字已正确存储为字节数组,第二项显示由相同位创建的BigInt,最后一项是相同的BigInt,但使用十六进制以更好地显示浮动点数据格式。

一旦您将这样的number 转换为BigInt(不是相同的数值,而是相同的位串),每个可能的数字值都将被唯一地表示。

您在上述算法中使用的相同位运算符将适用于BigInts,但没有 32 位限制。我猜想为了获得最佳效果,您需要将代码中的 32 更改为 64,并使用 16 位(而不是 8 位)十六进制常量作为哈希键。

【讨论】:

    猜你喜欢
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 2011-11-16
    • 2017-07-21
    • 2014-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多