Możliwe jest wykonanie matematyki wektorowej z dwiema liczbami spakowanymi w jedną. Najpierw pokażę przykład, zanim wyjaśnię, jak to działa:
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");
Korzystam z faktu, że jeśli przesuniesz nieco dwie liczby X razy, a następnie dodasz lub odejmiesz je przed przesunięciem z powrotem, otrzymasz ten sam wynik, jakbyś ich nie przesunął na początku. Podobnie mnożenie i dzielenie przez skalar działa symetrycznie dla przesuniętych wartości.
Liczba JavaScript ma 52 bity z dokładnością do liczb całkowitych (64-bitowe liczby zmiennoprzecinkowe), więc umieszczę jedną liczbę w wyższych dostępnych 26 bitach, a jedną w niższych. Kod jest trochę bardziej niechlujny, ponieważ chciałem obsługiwać podpisane numery.
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;
}
}
Jedynym minusem, jaki widzę w tym przypadku, jest to, że x i y muszą mieścić się w zakresie + -33 miliony, ponieważ muszą mieścić się w 26 bitach każdy.