Можна робити векторну математику з двома числами, упакованими в одне. Спершу покажу приклад, перш ніж пояснити, як це працює:
let a = vec_pack([2,4]);
let b = vec_pack([1,2]);
let c = a+b; // Vector addition
let d = c-b; // Vector subtraction
let e = d*2; // Scalar multiplication
let f = e/2; // Scalar division
console.log(vec_unpack(c)); // [3, 6]
console.log(vec_unpack(d)); // [2, 4]
console.log(vec_unpack(e)); // [4, 8]
console.log(vec_unpack(f)); // [2, 4]
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 біт кожен.