Можно выполнять векторные математические вычисления с двумя числами, упакованными в одно. Позвольте мне сначала показать пример, прежде чем я объясню, как это работает:
let a = vec_pack([2,4]);
let b = vec_pack([1,2]);
let c = a+b;
let d = c-b;
let e = d*2;
let f = e/2;
console.log(vec_unpack(c));
console.log(vec_unpack(d));
console.log(vec_unpack(e));
console.log(vec_unpack(f));
if(a === f) console.log("Equality works");
if(a > b) console.log("Y value takes priority");
Я использую тот факт, что если вы сдвинете два числа X раз по битам, а затем сложите или вычтите их перед обратным смещением, вы получите тот же результат, как если бы вы не сдвигали их с самого начала. Точно так же скалярное умножение и деление работают симметрично для сдвинутых значений.
Число JavaScript имеет 52 бита целочисленной точности (64-битные числа с плавающей запятой), поэтому я упакую одно число в более высокие доступные 26 бит, а другое - в более низкие. Код стал немного более запутанным, потому что я хотел поддерживать числа со знаком.
function vec_pack(vec){
return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);
}
function vec_unpack(number){
switch(((number & 33554432) !== 0) * 1 + (number < 0) * 2){
case(0):
return [(number % 33554432),Math.trunc(number / 67108864)];
break;
case(1):
return [(number % 33554432)-33554432,Math.trunc(number / 67108864)+1];
break;
case(2):
return [(((number+33554432) % 33554432) + 33554432) % 33554432,Math.round(number / 67108864)];
break;
case(3):
return [(number % 33554432),Math.trunc(number / 67108864)];
break;
}
}
Единственный недостаток, который я вижу в этом, заключается в том, что x и y должны находиться в диапазоне + -33 миллиона, так как они должны соответствовать 26 битам каждый.