我已经在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中使用类似的简单确定性函数吗?
答案 0 :(得分:1)
潜在的问题是,在javascript中,没有整数-因此所有数学函数都使用数字(52位精度浮点数)完成
在c#中,如果您使用多头,那么所有溢出都将被丢弃
在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 :(得分:0)
恐怕您的代码超出了整数的最大大小限制。一旦发生这种情况,它将返回1,因为计算((n*(n*n*60493 + 19990303) + 1376312589) & 0x7fffffff)/1073741824
将始终为0-因此1-0 = 1
答案 2 :(得分:0)
要了解这里发生的情况,必须检查JavaScript number
类型。它基本上是一个53位整数,使用另一个11位整数向左/向右移位,得到一个64位数字。因此,如果您的计算结果为54位整数,则只需要高位 53位,然后将它们左移1位。现在,如果对数字进行按位数学运算,则需要较低的32位。因此,如果整数大于84位,则对其进行按位移位将始终为0。因此,在进行按位运算时,JS中大于32位的数字将趋于0,而C#始终采用较低的32位,因此结果为精确到那些32位(但不能表示更大的数字)。
(2 + 2 ** 53) & (2 + 2 ** 53) // 2
(2 + 2 ** 54) & (2 + 2 ** 54) // 0
答案 3 :(得分:-2)
编辑(很抱歉以前的回答很差): 正如其他人之前所说,问题也与您的JS Number的大小有关。 如果您的代码在C#中工作,建议将功能转移到ASP.NET后端,该后端将通过某种API处理计算并转发结果