트릭은 부동 소수점 숫자의 비트를 정수 로 다시 해석하고 다시 형식화 된 배열 기능 을 사용하여 JavaScript에서 가능한 여러 숫자보기가있는 원시 바이트 버퍼를 작성하는 것에 의존 합니다.
다음은 당신이 준 코드의 문자 변환입니다. JavaScript의 모든 산술 연산은 32 비트가 아닌 64 비트 부동 소수점이므로 입력이 반드시 변환되므로 정확히 동일하지는 않습니다. 또한 원래 코드와 마찬가지로 프로세서 아키텍처가 다른 바이트 순서를 사용하는 경우 넌센스 결과를 제공한다는 점에서 플랫폼에 따라 다릅니다 . 이와 같은 작업을 수행 해야하는 경우 먼저 응용 프로그램에서 테스트 케이스를 실행하여 정수 및 부동 소수점에 예상 바이트 바이트 표시가 있는지 확인하는 것이 좋습니다.
const bytes = new ArrayBuffer(Float32Array.BYTES_PER_ELEMENT);
const floatView = new Float32Array(bytes);
const intView = new Uint32Array(bytes);
const threehalfs = 1.5;
function Q_rsqrt(number) {
const x2 = number * 0.5;
floatView[0] = number;
intView[0] = 0x5f3759df - ( intView[0] >> 1 );
let y = floatView[0];
y = y * ( threehalfs - ( x2 * y * y ) );
return y;
}
나는 이것이 합리적인 수치 결과를 제공한다는 그래프를 눈으로 확인했습니다. 그러나 더 높은 수준의 JavaScript 작업을 수행하고 있기 때문에 성능이 전혀 향상되지는 않을 것입니다. 편리한 브라우저에서 벤치 마크를 실행 Q_rsqrt(number)
했으며 1/sqrt(number)
(2018 년 4 월 현재 macOS의 Chrome, Firefox 및 Safari) 소요 시간의 50 % ~ 80 %가 소요됩니다 . 다음은 완전한 테스트 설정입니다.
const {sqrt, min, max} = Math;
const bytes = new ArrayBuffer(Float32Array.BYTES_PER_ELEMENT);
const floatView = new Float32Array(bytes);
const intView = new Uint32Array(bytes);
const threehalfs = 1.5;
function Q_rsqrt(number) {
const x2 = number * 0.5;
floatView[0] = number;
intView[0] = 0x5f3759df - ( intView[0] >> 1 );
let y = floatView[0];
y = y * ( threehalfs - ( x2 * y * y ) );
return y;
}
// benchmark
const junk = new Float32Array(1);
function time(f) {
const t0 = Date.now();
f();
const t1 = Date.now();
return t1 - t0;
}
const timenat = time(() => {
for (let i = 0; i < 5000000; i++) junk[0] = 1/sqrt(i)
});
const timeq = time(() => {
for (let i = 0; i < 5000000; i++) junk[0] = Q_rsqrt(i);
});
document.getElementById("info").textContent =
"Native square root: " + timenat + " ms\n" +
"Q_rsqrt: " + timeq + " ms\n" +
"Ratio Q/N: " + timeq/timenat;
// plot results
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
function plot(f) {
ctx.beginPath();
const mid = canvas.height / 2;
for (let i = 0; i < canvas.width; i++) {
const x_f = i / canvas.width * 10;
const y_f = f(x_f);
const y_px = min(canvas.height - 1, max(0, mid - y_f * mid / 5));
ctx[i == 0 ? "moveTo" : "lineTo"](i, y_px);
}
ctx.stroke();
ctx.closePath();
}
ctx.strokeStyle = "black";
plot(x => 1/sqrt(x));
ctx.strokeStyle = "yellow";
plot(x => Q_rsqrt(x));
<pre id="info"></pre>
<canvas width="300" height="300" id="canvas"
style="border: 1px solid black;"></canvas>