«1. Введение

Двоичная система счисления использует 0 и 1 для представления чисел. Компьютеры используют двоичные числа для хранения и выполнения операций над любыми данными.

В этом уроке мы узнаем, как преобразовать двоичное число в десятичное и наоборот. Кроме того, мы будем выполнять сложение и вычитание на них.

2. Двоичный литерал

В Java 7 появился двоичный литерал. Это упростило использование двоичных чисел.

Чтобы использовать его, нам нужно добавить к числу префикс 0B или 0b:

@Test
public void given_binaryLiteral_thenReturnDecimalValue() {

    byte five = 0b101;
    assertEquals((byte) 5, five);

    short three = 0b11;
    assertEquals((short) 3, three);

    int nine = 0B1001;
    assertEquals(9, nine);

    long twentyNine = 0B11101;
    assertEquals(29, twentyNine);

    int minusThirtySeven = -0B100101;
    assertEquals(-37, minusThirtySeven);

}

3. Преобразование двоичного числа

В этом разделе мы узнаем, как преобразовать двоичное число в его десятичный формат. и наоборот. Здесь мы сначала воспользуемся встроенной функцией Java для преобразования, а затем напишем для нее собственные методы.

3.1. Преобразование десятичного числа в двоичное

Integer имеет функцию toBinaryString для преобразования десятичного числа в двоичную строку:

@Test
public void given_decimalNumber_then_convertToBinaryNumber() {
    assertEquals("1000", Integer.toBinaryString(8));
    assertEquals("10100", Integer.toBinaryString(20));
}

Теперь мы можем попытаться написать собственную логику для этого преобразования. Прежде чем писать код, давайте сначала разберемся, как преобразовать десятичное число в двоичное.

Чтобы преобразовать десятичное число n в его двоичный формат, нам нужно:

  1. Divide n by 2, noting the quotient q and the remainder r
  2. Divide q by 2, noting its quotient and remainder
  3. Repeat step 2 until we get 0 as the quotient
  4. Concatenate in reverse order all remainders

Давайте посмотрим на пример преобразования 6 в его эквивалент в двоичном формате:

  1. First, divide 6 by 2: quotient 3, remainder 0
  2. Then, divide 3 by 2: quotient 1, remainder 1
  3. And finally, divide 1 by 2: quotient 0, remainder 1
  4. 110

Давайте теперь реализуем описанный выше алгоритм:

public Integer convertDecimalToBinary(Integer decimalNumber) {

    if (decimalNumber == 0) {
        return decimalNumber;
    }

    StringBuilder binaryNumber = new StringBuilder();
    Integer quotient = decimalNumber;

    while (quotient > 0) {
        int remainder = quotient % 2;
        binaryNumber.append(remainder);
        quotient /= 2;
    }

    binaryNumber = binaryNumber.reverse();
    return Integer.valueOf(binaryNumber.toString());
}

3.2. Преобразование двоичного числа в десятичное число

Для разбора двоичной строки класс Integer предоставляет функцию parseInt:

@Test
public void given_binaryNumber_then_ConvertToDecimalNumber() {
    assertEquals(8, Integer.parseInt("1000", 2));
    assertEquals(20, Integer.parseInt("10100", 2));
}

Здесь функция parseInt принимает на вход два параметра:

  1. Binary string to be converted
  2. Radix or base of the number system in which input string has to be converted

Теперь давайте попробуем написать свою собственную логика для преобразования двоичного числа в десятичное:

  1. Start from with rightmost digit
  2. Multiply each digit with 2^{position} of that digit – here, rightmost digit’s position is zero and it increases as we move to the left side
  3. Add the result of all the multiplications to get the final decimal number

Снова давайте посмотрим на наш метод в действии:

  1. First, 101011 = (1*2^5) + (0*2^4)  + (1*2^3) + (0*2^2) + (1*2^1) + (1*2^0)
  2. Next, 101011 = (1*32) + (0*16) + (1*8) + (0*4)  + (1*2) + (1*1)
  3. Then, 101011 = 32 + 0 + 8 + 0 + 2 + 1
  4. And finally, 101011 = 43

Давайте, наконец, закодируем описанные выше шаги:

public Integer convertBinaryToDecimal(Integer binaryNumber) {

    Integer decimalNumber = 0;
    Integer base = 1;

    while (binaryNumber > 0) {
        int lastDigit = binaryNumber % 10;
        binaryNumber = binaryNumber / 10;
        decimalNumber += lastDigit * base;
        base = base * 2;
    }
    return decimalNumber;
}

4. Арифметические операции

В этом разделе мы Сконцентрируемся на выполнении арифметических операций над двоичными числами.

4.1. Сложение

Как и при сложении десятичных чисел, мы начинаем складывать числа с самой правой цифры.

При сложении двух двоичных цифр необходимо помнить следующие правила:

    0 + 0 = 0 0 + 1 = 1 1 + 1 = 10 1 + 1 + 1 = 11

Эти правила можно реализовать как:

public Integer addBinaryNumber(Integer firstNum, Integer secondNum) {
    StringBuilder output = new StringBuilder();
    int carry = 0;
    int temp;
    while (firstNum != 0 || secondNum != 0) {
        temp = (firstNum % 10 + secondNum % 10 + carry) % 2;
        output.append(temp);

        carry = (firstNum % 10 + secondNum % 10 + carry) / 2;
        firstNum = firstNum / 10;
        secondNum = secondNum / 10;
    }
    if (carry != 0) {
        output.append(carry);
    }
    return Integer.valueOf(output.reverse().toString());
}

4.2. Вычитание

Есть много способов вычитания двоичных чисел. В этом разделе мы изучим метод дополнения до единицы для выполнения вычитания.

Давайте сначала разберемся, что такое дополнение числа.

Дополнение числа до единицы — это число, полученное путем инвертирования каждой цифры двоичного числа. Это означает, что просто замените 1 на 0 и 0 на 1:

public Integer getOnesComplement(Integer num) {
    StringBuilder onesComplement = new StringBuilder();
    while (num > 0) {
        int lastDigit = num % 10;
        if (lastDigit == 0) {
            onesComplement.append(1);
        } else {
            onesComplement.append(0);
        }
        num = num / 10;
    }
    return Integer.valueOf(onesComplement.reverse().toString());
}

Чтобы выполнить вычитание двух двоичных чисел с использованием дополнения до единицы, нам нужно:

  1. Calculate the one’s complement of the subtrahend s
  2. Add s and the minuend
  3. If a carry gets generated in step 2, then add that carry to step 2’s result to get the final answer.
  4. If a carry is not generated in step 2, then the one’s complement of step 2’s result is the final answer. But in this case, the answer is negative

Давайте реализуем описанные выше шаги:

public Integer substractBinaryNumber(Integer firstNum, Integer secondNum) {
    int onesComplement = Integer.valueOf(getOnesComplement(secondNum));
    StringBuilder output = new StringBuilder();
    int carry = 0;
    int temp;
    while (firstNum != 0 || onesComplement != 0) {
        temp = (firstNum % 10 + onesComplement % 10 + carry) % 2;
        output.append(temp);
        carry = (firstNum % 10 + onesComplement % 10 + carry) / 2;

        firstNum = firstNum / 10;
        onesComplement = onesComplement / 10;
    }
    String additionOfFirstNumAndOnesComplement = output.reverse().toString();
    if (carry == 1) {
        return addBinaryNumber(Integer.valueOf(additionOfFirstNumAndOnesComplement), carry);
    } else {
        return getOnesComplement(Integer.valueOf(additionOfFirstNumAndOnesComplement));
    }
}

5. Заключение

В этой статье мы научились преобразовывать двоичные числа в десятичные и обратно. Затем мы выполнили арифметические операции, такие как сложение и вычитание над двоичными числами.

Полный код, используемый в этой статье, доступен на GitHub.