Зачем нам нужно использовать операторы сдвига в java?

  • Какова цель использования операторов Shift вместо использования деления и умножения?

  • Есть ли другие преимущества использования операторов сдвига?

  • Где можно попытаться использовать оператор сдвига?

Ответ 1

Разделение и умножение на самом деле не используются операторами битового сдвига. Это устаревшая "оптимизация", которую некоторые хотели бы применить.

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

Например, скажем, у меня есть два байта, которые представляют собой байты высокого и младшего разрядов двухбайтового (16-разрядного) значения без знака. Скажем, вам нужно построить это значение. В Java это:

int high = ...;
int low = ...;
int twoByteValue = (high << 8) | low;

Вы не могли бы сделать это без оператора сдвига.

Чтобы ответить на ваши вопросы: вы используете их там, где вам нужно их использовать! и нигде больше.

Ответ 2

Оператор сдвига используется, когда вы выполняете операции с логическими битами, в отличие от математических операций.

Он может использоваться для скорости, будучи значительно быстрее, чем деление/умножение при работе с операндами, обладающими мощностью двух, но ясность кода обычно предпочтительнее, чем скорость raw.

Ответ 4

Это полезно при построении значений, которые представляют собой комбинацию чисел, где биты группируются как разные значения. (Ответ Шона Оуэна объясняет это лучше.)

Например, работа с цветами, которые:

  • "#AARRGGBB" как строка base16
  • 0xAAAARRRRGGGGBBBB как целое число

В своем целочисленном формате вы можете использовать shift для получения фактического значения компонента целого числа в качестве полезного числа.

public static int stringToColor(String s) throws JSExn {
    // string starts with '#' - parse integer from string
    try {
        // used to build up the return value
        int a, r, g, b;

        switch (s.length()) {
        case 4:
            a = 0xFF000000;
            r = Integer.parseInt(s.substring(1, 2), 16);
            r = r << 16 | r << 20;
            b = Integer.parseInt(s.substring(2, 3), 16);
            b = b << 8 | b << 12;
            g = Integer.parseInt(s.substring(3, 4), 16);
            g = g | g << 4;
            break;
        case 5:
            a = Integer.parseInt(s.substring(1, 2), 16);
            a = a << 24 | a << 28;
            r = Integer.parseInt(s.substring(2, 3), 16);
            r = r << 16 | r << 20;
            b = Integer.parseInt(s.substring(3, 4), 16);
            b = b << 8 | b << 12;
            g = Integer.parseInt(s.substring(4, 5), 16);
            g = g | g << 4;
            break;
        case 7:
            a = 0xFF000000;
            r = Integer.parseInt(s.substring(1, 3), 16) << 16;
            b = Integer.parseInt(s.substring(3, 5), 16) << 8;
            g = Integer.parseInt(s.substring(5, 7), 16);
            break;
        case 9:
            a = Integer.parseInt(s.substring(1, 3), 16) << 24;
            r = Integer.parseInt(s.substring(3, 5), 16) << 16;
            b = Integer.parseInt(s.substring(5, 7), 16) << 8;
            g = Integer.parseInt(s.substring(7, 9), 16);
            break;
        default:
            throw new JSExn("Not a valid color: '"+s+"'");
        }

        // return our integer ARGB
        return a | r | b | g;
}

Ответ 5

Снижение прочности происходит, когда операция заменяется эквивалентной операцией, которая выполняется быстрее.

  • заменяя целочисленное деление или умножение на степень 2 с арифметическим сдвигом или логическим сдвигом.
  • заменяет целочисленное умножение на константу с комбинацией сдвигов, добавляет или вычитает.
  • заменяет целочисленное деление на константу с умножением, используя ограниченный диапазон целых чисел.

Почему это неправильно?

1. Снижает производительность по мере увеличения времени, необходимого для расчета. 2. Арифметические операции, такие как деление и умножение, медленнее. 3. Дорогостоящие операции

Преимущества

  • Повышает производительность.
  • Более быстрые вычисления.

DeMerit

  • Считывание кода уменьшается.

Ответ 6

Полезно, когда вы имеете дело с флагами, вы можете сохранить только одну переменную int информацию об активных флагах, см. ниже:

public class DealingWithShiftOperators {

    public static void main(String[] args) {

        int active_flags = 10;

        printActiveFlags(active_flags);

    }

    public static void printActiveFlags(int active_flags) {

        final int TOTAL_FLAGS = 8;
        final int MAX_VALUE = 1 << TOTAL_FLAGS;
        final int MIN_VALUE = 1;

        int current_flag = MAX_VALUE;

        do {
            current_flag = current_flag >> 1;

            if (active_flags - current_flag < 0) {
                System.out.println(current_flag + ": off");
            } else {
                active_flags = active_flags - current_flag;
                System.out.println(current_flag + ": on");
            }

        } while (current_flag > MIN_VALUE);

    }

}

В приведенном выше примере выводится следующее:

128: off
64: off
32: off
16: off
8: on
4: off
2: on
1: off

Как вы можете видеть, active_flags - это номер 2 и номер 8. Мы сохранили эту информацию только в одной переменной, ее значение равно 10 (8 + 2).