【问题标题】:Javascript - will this noise function work?Javascript - 这个噪音功能会起作用吗?
【发布时间】:2019-09-06 11:05:40
【问题描述】:

我有一段时间在 C# 和 C++ 地形生成器中使用了以下确定性噪声函数:

float GridNoise(int x, int z, int seed)
{
    int n = (1619*x + 31337*z + 1013*seed) & 0x7fffffff;
    n = (n >> 13) ^ n;

    return 1 - ((n*(n*n*60493 + 19990303) + 1376312589) & 0x7fffffff)/(float)1073741824;
}

对于我输入的任何整数 x/z 坐标,它都会返回一个介于 1 和 -1 之间的“随机”浮点数(另外还有一个种子,因此我可以生成不同的地形)。我尝试在 Javascript 中实现相同的功能,但结果不如预期。对于较小的值,这似乎还可以,但是当我使用较大的值(约 10000 的数量级)时,结果的随机性越来越小,最终它返回的都是 1。

您可以看到它在 C# here 中正常工作,而同一输入 here 的 JS 结果不正确。

我怀疑这与 JS 变量不是严格整数有关,但任何人都可以阐明更多信息吗?如果这不起作用,是否有人可以在 JS 中使用类似的简单确定性函数?

【问题讨论】:

  • (n*(n*n*60493 + 19990303)+ 1376312589) & 0x7fffffff 始终为 0,因为 (n*(n*n*60493 + 19990303)+ 1376312589) 就像 6e+25 - 所以,没有办法在 javascript 中工作
  • return 1 - ((n*(n*n*60493 & 0x7fffffff + 19990303) + 1376312589) & 0x7fffffff)/1073741824; 将限制为 -1 ... +1

标签: javascript random noise


【解决方案1】:

根本问题是,在 javascript 中,没有整数 - 所以所有数学函数都是使用 Number(52 位精度浮点数)完成的

在 c# 中,如果您使用的是 long,那么任何溢出都会被丢弃

在javascript中,你需要自己处理这个

有一种数字格式将出现在浏览器中,这会有所帮助,但它还没有出现 - BigInt ...它在 chrome/opera 中,在 firefox(桌面,不是 android)的标志后面

(没有关于 Edge(反正死了)或 Safari(新 IE)的消息——当然,IE 永远不会得到它们)

使用BigInt我能想到的最好的方法是

function gridNoise(x, z, seed) {
    var n = (1619 * x + 31337 * z + 1013 * seed) & 0x7fffffff;
    n = BigInt((n >> 13) ^ n);
    n = n * (n * n * 60493n + 19990303n) + 1376312589n;
    n = parseInt(n.toString(2).slice(-31), 2);
    return 1 - n / 1073741824;
}

function test() {
    for (var i = 10000; i < 11000; i++) {
        console.log(gridNoise(0, 0, i));
    }
}
test();

注意,60493nBigInt 符号

您可以在过渡期间使用“大整数”库 - https://github.com/peterolson/BigInteger.js

以下内容不起作用,并且永远不会……因为 32 位 x 32 位 == 64 位……所以你已经丢失了位

我误读了代码,虽然 n 只有 19 位(因为 >>13)

罢工>

如果您将 n * n * 60493 的结果限制为 32 位,(实际上,我将其设置为 31 位...所以.. 无论如何它似乎可以正常工作

function gridNoise(x, z, seed) {
  var n = (1619 * x + 31337 * z + 1013 * seed) & 0x7fffffff;
  n = (n >> 13) ^ n;

  return 1 - ((n * (n * n * 60493 & 0x7fffffff + 19990303) + 1376312589) & 0x7fffffff) / 1073741824;
}

这也有效

return 1 - ((n*(n*n*60493 | 0 + 19990303)  + 1376312589) & 0x7fffffff)/1073741824;

这将中间结果限制为 32 位,这可能是也可能不是“准确”

如果您想准确复制 c# 生成的内容,您可能需要使用它

【讨论】:

  • 不幸的是,从 BigInts 获取低 32 位并不容易。 parseInt(bigint.toString(2).slice(-32), 2) 可能有用
  • @JonasWilms - 就是这么简单:p 注意,在代码中它只有 31 位 &amp; 0x7fffffff
【解决方案2】:

恐怕您的代码超出了整数的最大大小限制。一旦发生这种情况,它就会返回 1,因为计算 ((n*(n*n*60493 + 19990303) + 1376312589) &amp; 0x7fffffff)/1073741824 将始终为 0 - 因此 1 - 0 = 1

【讨论】:

    【解决方案3】:

    要了解这里发生了什么,必须检查 JavaScript 的 number 类型。它基本上是一个 53 位整数,使用另一个 11 位整数左移/右移,得到一个 64 位数字。因此,如果您的计算会产生一个 54 位整数,它只需要 高位 53 位,并将它们左移 1。现在,如果您对数字进行按位数学运算,它将需要 低 32 位。因此,如果一个整数大于 84 位,对其进行按位移位将始终为 0。因此,大于 32 位的数字在 JS 中进行按位运算时将趋于 0,而 C# 始终采用较低的 32 位,因此结果将是对于那些 32 位是准确的(但无法表示更大的数字)。

      (2 + 2 ** 53) & (2 + 2 ** 53)  // 2
      (2 + 2 ** 54) & (2 + 2 ** 54) // 0
    

    【讨论】:

      【解决方案4】:

      编辑(抱歉之前的回答很差): 正如其他人之前所说的那样,您的值也超过了 JS Number 的大小。 如果您的代码在 C# 中工作,建议将功能卸载到 ASP.NET 后端,该后端将处理计算并通过某种 API 转发结果

      【讨论】:

      • 我的意思是回调不是承诺。很抱歉造成混乱
      • 不,即使那样你也错了......而且你的代码甚至不是javascript
      • 哦,你的权利。与 ppl xD 聊天时,我不应该在茶歇时回答问题
      • 您知道可以删除答案吗?这可能应该被删除,因为(1)它不是 JavaScript(2)如果它应该是打字稿,它包含 SyntaxErrors(3)它谈论承诺,但在代码中根本不使用承诺(4)问题与承诺无关(5) 对JS和C#中的执行做出错误的陈述
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-04
      • 1970-01-01
      • 2023-03-04
      • 2015-01-28
      • 2017-10-12
      • 1970-01-01
      相关资源
      最近更新 更多