Uczymy się konwersji binarnych na dziesiętne wykorzystując zapis 2s complement, jedyny słuszny gdzie nie ma ujemnego zera. Do dzieła.

Jak działa twos complement:

  • Jeżeli pierwsza z lewej to 0 to dla reszty wylicz wartość jak dla unsigned integer
  • Jeżeli pierwsza z lewej to 1 to:
    • Dla reszty wylicz wartość
    • Dodaj 1
    • Pomnóż przez -1 pamiętając, że chcesz ujemną

Ogarnijmy funkcję 1s compelemnt z poprzedniego przykładu:

function bin2decOnes(binArr){

    let sign = binArr[0];

    function onesComplement(binArr){

        return binArr.map((n) => {
            return n === 0 ? 1 : 0
        });
    }

    function _bin2dec(binArr){

        let base = 2;
        let position = 0;
    
        let weight;
    
        let decimalNumber = 0;
    
        while(binArr.length > 0){
    
            let lastDigit = binArr.pop();
    
            weight = Math.pow(base, position);
    
            decimalNumber += lastDigit * weight;
    
            position++;
            
        }
    
        return decimalNumber;
    }

    if(sign === 0)
        return _bin2dec(binArr.slice(1));

    return -1 * bin2decOnes(onesComplement(binArr));
}

Ok, fajnie, metodą prób i błędów możemy zbudować 2s compelement:

function bin2dec2s(binArr){

    let sign = binArr[0];

    function onesComplement(binArr){

        return binArr.map((n) => {
            return n === 0 ? 1 : 0
        });
    }

    function _bin2dec(binArr){

        let base = 2;
        let position = 0;
    
        let weight;
    
        let decimalNumber = 0;
    
        while(binArr.length > 0){
    
            let lastDigit = binArr.pop();
    
            weight = Math.pow(base, position);
    
            decimalNumber += lastDigit * weight;
    
            position++;
            
        }
    
        return decimalNumber;
    }

    if(sign === 0)
        return _bin2dec(binArr.slice(1));

    return -1 * bin2dec2s(onesComplement(binArr)) -1;
}

Ta funkcja nie jest czytelna, natomiast zobaczmy, czy spełnia swoje przeznaczenie:

console.log(bin2dec2s([1,1,0,1]));
//-3
console.log(bin2dec2s([0,0,1,1]));
//3

0011 to 3 bo 011 to 3.

1101… 0010 to 2. Dodaj 1 to 3. Razy -1 to -3.

Okej, fajnie, ale nieczytelnie. My tam odejmujemy, nie dodajemy. Nie idzie się w tym połapać:


function bin2dec2s(binArr){

    let sign = binArr[0];

    function onesComplement(binArr){

        return binArr.map((n) => {
            return n === 0 ? 1 : 0
        });
    }

    function _bin2dec(binArr){

        let _sign = binArr[0];

        if(_sign === 1)
            binArr = onesComplement(binArr);

        let base = 2;
        let position = 0;
    
        let weight;
    
        let decimalNumber = 0;
    
        while(binArr.length > 1){
    
            let lastDigit = binArr.pop();
    
            weight = Math.pow(base, position);
    
            decimalNumber += lastDigit * weight;
    
            position++;
            
        }

        if(_sign === 0)
            return decimalNumber;

        return decimalNumber + 1;
    }

    if(sign === 0)
        return _bin2dec(binArr);

    return -1 * _bin2dec(binArr);
}

console.log(bin2dec2s([1,1,0,1]));
//-3
console.log(bin2dec2s([0,0,1,1]));
//3

No tu już lepiej. Czyli:

  • 0 na początku? Ok, w _bin2dec olewamy 0 po lewej i wyliczamy tradycyjnie resztę
  • 1 na początku? _bin2dec zrobi podmianę bitów, wyliczy dla reszty cyfr liczbę i doda 1
  • Jak była dodatnia to zwróć _bin2dec
  • Jak miała 1 na początku to musi być ujemna

Polecam to sobie z kartką papieru wyliczyć. Inaczej nigdy tego nie zrozumiemy.

A jest to dużo łatwiejsze, niż nauka Reacta, gdy się nie wie, czym jest funkcja bind albo eventy w JS.

Albo nauka tailwinda/bootstrapa, gdy się zwykłego CSS nie ogarnia. Dzisiaj wszyscy programiści tacy…