Hile , kayan nokta sayısının bitlerini tamsayı olarak yeniden yorumlamaya ve tekrar yazılır, bu da JavaScript'te Yazılan Diziler özelliğini kullanarak mümkün olan birden fazla sayısal görünüme sahip bir ham bayt tamponu oluşturmak için mümkündür.
İşte verdiğiniz kodun gerçek bir dönüşümü; JavaScript'teki tüm aritmetik işlemler 32 bit değil, 64 bit kayan nokta olduğundan, tam olarak aynı olmadığını unutmayın, bu nedenle giriş mutlaka dönüştürülecektir. Ayrıca, orijinal kod gibi, bu, işlemci mimarisi farklı bir bayt sırası kullanıyorsa saçma sonuçlar vereceği için platforma bağlıdır ; böyle bir şey yapmanız gerekiyorsa, uygulamanızın önce tamsayıların ve kayan noktaların beklediğiniz bayt gösterimlerine sahip olduğunu belirlemek için bir test durumu yürütmesini öneririz.
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;
}
Bir grafiğe göz atarak bunun makul sayısal sonuçlar verdiğini onayladım. Bununla birlikte, daha yüksek düzeyli JavaScript işlemleri yaptığımızdan, bunun performansı artıracağı açık değildir. Kullantığım tarayıcılarda karşılaştırmalar yaptım ve Nisan 2018 itibariyle macOS'ta Chrome, Firefox ve Safari Q_rsqrt(number)
tarafından alınan sürenin% 50 ila% 80'ini aldığını gördüm 1/sqrt(number)
. İşte tam test kurulumum:
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>