我有一个确定性的噪声函数,我已经在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中使用,如果这不起作用?
根本问题是,在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();
注意,60493n
是BigInt
表示法
你可以在过渡期间使用“大整数”库 - https://github.com/peterolson/BigInteger.js
以下不起作用,永远不会...因为32位x 32位== 64位...所以你已经丢失了比特
我误读了代码,虽然
n
只有19位(因为>> 13)
如果你将n * n * 60493的结果限制为32bit,(实际上,我把它设为31bit ......所以..无论如何它似乎工作正常
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#产生的确切内容,你可能需要使用它
我担心你的代码超过了整数的最大大小限制。一旦发生这种情况,它就会返回1,因为计算((n*(n*n*60493 + 19990303) + 1376312589) & 0x7fffffff)/1073741824
将始终为0 - 因此1 - 0 = 1
要了解这里发生的事情,我们必须检查JavaScripts 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
编辑(对不起之前的答案感到抱歉):正如其他人之前所说的那样,问题也与您的超出JS编号大小的值有关。如果您的代码在C#中工作,那么建议将功能卸载到ASP.NET后端,后端将通过某种API处理计算结果。