Closed foretoo closed 2 years ago
@foretoo
x | 0
does exactly the same asMath.floor(x)
but much faster.
That's not true. Math.floor(-0.1)
is -1. -0.1|0
is 0. In practice using |0
leads to a discontinuity around 0 because of that.
That's also why the tests fail. :)
The in simplex noise demystified Stefan Gustavson uses the following
// This method is a *lot* faster than using (int)Math.floor(x)
private static int fastfloor(double x) {
return x>0 ? (int)x : (int)x-1;
}
That mostly works except for the fact that negative integers now also get rounded down so fastfloor(-1) is -2. That shouldn't be a problem for the smoothness of the output but it also changes the results. In the end it also wasn't much faster. By giving up a bit we could do something like ((x + pad)|0) - pad; Where pad = 1<<30. That could be faster since it doesn't require any branching. I might give that a try later.
➜ /workspaces/simplex-noise.js/perf (main ✗) $ ./benchmark.sh
33932097.10748968
noise2D: 66,808,990 ops/sec ±0%
noise3D: 44,500,140 ops/sec ±0%
noise4D: 32,128,885 ops/sec ±0%
➜ /workspaces/simplex-noise.js/perf (main ✗) $ ./benchmark.sh
34228639.807571135
noise2D: 66,613,371 ops/sec ±0%
noise3D: 44,476,135 ops/sec ±0%
noise4D: 32,093,893 ops/sec ±0%
Gave it a try. First is the weird Math.floor(x)|0, second is ((x + (1 << 30)) | 0) - (1 << 30)
. There isn't any noticeable performance difference. I don't think there is much to be gained here that would justify a change to the output.
huh didn't know about that difference 😅 but still, i believe it depends on environment, because when i run
for (let t = 0; t < 5; t++) {
console.time(`${t}`)
for (let i = 0; i < 1000000; i++) {
noise2D(i, 0)
}
console.timeEnd(`${t}`)
}
with Math.floor(x)|0
, i get ~
0: 87.362ms
1: 83.46ms
2: 76.005ms
3: 75.335ms
4: 77.59ms
and with ((x + 1<<30)|0) - 1<<30
, i get ~
0: 73.613ms
1: 47.618ms
2: 42.436ms
3: 42.588ms
4: 43.477ms
Macbook Pro 13" (2020), Node v18.7.0 same difference in Chrome 104.0.5112.79
oh, i see, i messed up, instead of ((x + (1 << 30)) | 0) - (1 << 30)
i used ((x + 1<<30)|0) - 1<<30
, well then there is no noticeable difference indeed. =)
Operator precedence isn't always intuitive. :) I tend to run the tests before I run benchmarks so I catch issues like that.
Even if this one didn't pan out, thanks for looking for an improvement. If you find something else you think could be improved just create another MR. :)
x | 0
does exactly the same asMath.floor(x)
but much faster. Don't know why you got ~10% speedup by combining both approaches, but definitely it would be even faster without calling Math.floor at all.