Wykonujemy proste, acz ciekawe ćwiczenie, które ma nam wypisać ileś wartości cyfr w systemie dwójkowym. Wiadomo, że pierwsza to 1, druga to 2, potem 4,8,16…
Ok, podejście pierwsze:
function valuesInBinary(num){
let values = [1];
while(num > 1){
let currVal = values[0] << 1;
values = [currVal, ...values];
num--;
}
return values;
}
console.log(valuesInBinary(8));
//[ 128, 64, 32, 16, 8, 4, 2, 1 ]
Jeżeli rozumiemy dlaczego daje wynik jaki daje to już jest bardzo dobrze. Ale programista musi rozumieć dużo więcej z tego, co się dzieje. Nie chodzi o optymalizację, ale o zrozumienie materii.
Zatem pytam:
- Co w tym algorytmie jest szybkiego?
- Co w tym algorytmie jest wolnego?
Cóż, szybki jest operator bitowy. Wolne? Przede wszystkim przesuwanie tablicy w prawo. Możemy to sobie rozrysować, ale dodanie elementu na końcu to zawsze O(1). Dodanie elementu na początku to zawsze przeindeksowanie wszystkich pozostałych elementów +1.
Ok, pomyślmy nad czymś innym. Niech używa, a bo ja wiem, Math.pow(2, n). Spróbujmy:
console.log(Array.from({length: 4}, (_, i) => {
return 1 * Math.pow(2, i);
}))
//[ 1, 2, 4, 8 ]
console.log(Array.from({length: 8}, (_, i) => {
return 1 * Math.pow(2, i);
}))
//[ 1, 2, 4, 8, 16, 32, 64, 128 ]
W złej kolejności to rośnie, chcemy pokazywać tak jak się pokazuje, czyli 1 najbardziej na prawo. Z drugiej strony chcemy dodawać te liczby w kolejności a nie przesuwać w prawo non-stop tablicę.
Jakiś pomysł? Polecam zawsze metodą prób i błędów. Zobaczmy na te nasze 1…128. Najmniejsza to 1 * 2^0 (1), największa to 1 * 2^7 (128).
Możemy pomyśleć albo potestować na czuja, koniec końców programiście to nie robi różnicy czy zrozumie swój program przed napisaniem czy po napisaniu, ważne żeby wszystko działało i było dogłębnie przetestowane:
console.log(Array.from({length: 8}, (_, i) => {
return 1 * Math.pow(2, 7-i);
}))
//[ 128, 64, 32, 16, 8, 4, 2, 1 ]
Teraz możemy napisać naszą funkcję:
function valuesInBinary_v2(num){
return Array.from({length: num}, (_, i) => {
return 1 * Math.pow(2, num-1-i);
});
}
console.log(valuesInBinary_v2(8));
//[ 128, 64, 32, 16, 8, 4, 2, 1 ]
No i mamy. Teraz można pod czymś takim podopisywać jedynki i zera i mamy ściągę do łatwiejszego bawienia się z binarnymi, zanim się z nimi oswoimy.