Как удалить девятую шестнадцатеричную ди git целого числа без использования строк? - PullRequest
1 голос
/ 25 апреля 2020

Рассмотрим шестнадцатеричное целочисленное значение, такое как n = 0x12345, как получить 0x1235 как результат, выполнив remove(n, 3) (big endian)?

Для входных данных выше я думаю, что это может быть достигнуто путем выполнения некоторые побитовые шаги:

  • partA = извлечь часть из индекса 0 до targetIndex - 1 (должен вернуть 0x123);
  • partB = извлечь часть от targetIndex + 1 до length(value) - 1 (0x5);
  • результат, затем может быть выражен как ((partA << length(partB) | partB), давая результат 0x1235.

Однако я Я до сих пор запутался в том, как это реализовать, когда каждый гекс di git занимает 4 пробела. Кроме того, я не знаю хорошего способа получить длину чисел.

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

Итак, каков хороший способ удаления без строк?

Ответы [ 3 ]

1 голос
/ 26 апреля 2020

Это работает, написав метод для удаления справа, но настраивая параметр для удаления слева. Бонус в том, что удаление справа также доступно для использования. Этот метод использует longs, чтобы максимизировать длину шестнадцатеричного значения.

long n = 0x12DFABCA12L;
int r = 3;
System.out.println("Supplied value: " + Long.toHexString(n).toUpperCase());
n = removeNthFromTheRight(n, r);
System.out.printf("Counting %d from the right: %X%n", r, n);
n = 0x12DFABCA12L;
n = removeNthFromTheLeft(n, r);
System.out.printf("Counting %d from the left:  %X%n", r, n);

Печать

Supplied value: 12DFABCA12
Counting 3 from the right: 12DFABA12
Counting 3 from the left:  12DABCA12

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

Этот метод считает справа.

public static long removeNthFromTheRight(long v, int n) {
    if (v <= 0) {
        throw new IllegalArgumentException("Not enough digits");
    }
    // save hex digit
    long k = v % 16;
    while (n > 0) {
    // continue removing digit until one
    // before the one you want to remove
    return removeNthFromTheRight(v / 16, n - 1) * 16 + k;
}
if (n == 0) {
    // and ignore that digit.
    v /= 16;
}
return v;
}

Этот метод считает слева. Он просто корректирует значение n, а затем вызывает removeFromTheRight.

public static long removeNthFromTheLeft(long v, int n) {
    ndigits = (67-Long.numberOfLeadingZeros(v))>>2;

    // Now just call removeNthFromTheRight with modified paramaters.
    return removeNthFromTheRight(v, ndigits - n - 1);
}

Вот моя версия, использующая битовые манипуляции с объяснением.

  • самый высокий набор бит помогает найти смещение для маски. Для long этот бит равен 64 числу ведущих нулей. Чтобы получить число шестнадцатеричных цифр, нужно разделить на 4. Чтобы учесть числа, равномерно делимые на 4, необходимо добавить 3 перед делением. Таким образом, получается число цифр:

    digits = (67-Long.numberOfLeadingZeros(i))>>2;
    , которое затем требует его настройки для маскировки соответствующих частей номера.

    offset = digits-i - 1

  • m - маска для маскирования ди git, который необходимо удалить. Поэтому начните с -1L (all hex 'F') и сдвига вправо 4*(16-offset) битов. Это приведет к маске, которая маскирует все справа от di git, чтобы быть удаленным. Примечание. Если offset равно 0, оператор сдвига будет 64, и биты не будут сдвигаться. Для этого операция сдвига разбита на две операции.

  • Теперь просто замаскируйте младшие биты v & m

  • и старший порядок биты смещены вправо 4 бит, чтобы исключить желаемую ди git. (v>>>4)^ ~m
  • , а затем две части просто ИЛИ вместе.
    static long remove(long v, int i) {
        int offset = ((67 - Long.numberOfLeadingZeros(v))>>2) - i - 1;
        long m = (-1L >>> (4*(16 - offset) - 1)) >> 1;
        return ((v >>> 4) & ~m) | (v & m);
    }
1 голос
/ 26 апреля 2020

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

int remove(int x, int i) {
    // create a mask covering the highest 1-bit and all lower bits
    int m = x;
    m |= (m >>> 1);
    m |= (m >>> 2);
    m |= (m >>> 4);
    m |= (m >>> 8);
    m |= (m >>> 16);
    // clamp to 4-bit boundary
    int l = m & 0x11111110;
    m = l - (l >>> 4);
    // shift to select relevant position
    m >>>= 4 * i;
    // assemble result
    return ((x & ~(m << 4)) >>> 4) | (x & m);
}

, где ">>>" - беззнаковое смещение.

В качестве примечания, если 0 указывает самый высокий шестнадцатеричный ди git в 32-битном слове, не зависящем от ввода это намного проще:

int remove(int x, int i) {
    int m = 0xffffffff >>> (4*i);
    return ((x & ~m) >>> 4) | (x & (m >>> 4));
}
1 голос
/ 25 апреля 2020

Решение:

Заменить операции с использованием 10 на операции с использованием 16.

Демонстрация

Использование побитового оператора:

public class Main {
    public static void main(String[] args) {
        int n = 0x12345;
        int temp = n;
        int length = 0;

        // Find length
        while (temp != 0) {
            length++;
            temp /= 16;
        }
        System.out.println("Length of the number: " + length);

        // Remove digit at index 3
        int m = n;
        int index = 3;
        for (int i = index + 1; i <= length; i++) {
            m /= 16;
        }
        m *= 1 << ((length - index - 1) << 2);
        m += n % (1 << ((length - index - 1) << 2));
        System.out.println("The number after removing digit at index " + index + ": 0x" + Integer.toHexString(m));
    }
}

Выход:

Length of the number: 5
The number after removing digit at index 3: 0x1235

Использование Math::pow:

public class Main {
    public static void main(String[] args) {
        int n = 0x12345;
        int temp = n;
        int length = 0;

        // Find length
        while (temp != 0) {
            length++;
            temp /= 16;
        }
        System.out.println("Length of the number: " + length);

        // Remove digit at index 3
        int m = n;
        int index = 3;
        for (int i = index + 1; i <= length; i++) {
            m /= 16;
        }
        m *= ((int) (Math.pow(16, length - index - 1)));
        m += n % ((int) (Math.pow(16, length - index - 1)));
        System.out.println("The number after removing digit at index " + index + ": 0x" + Integer.toHexString(m));
    }
}

Выход:

Length of the number: 5
The number after removing digit at index 3: 0x1235

JavaScript версия:

n = parseInt(12345, 16);
temp = n;
length = 0;

// Find length
while (temp != 0) {
    length++;
    temp = Math.floor(temp / 16);
}
console.log("Length of the number: " + length);

// Remove digit at index 3
m = n;
index = 3;
for (i = index + 1; i <= length; i++) {
    m = Math.floor(m / 16);
}
m *= 1 << ((length - index - 1) << 2);
m += n % (1 << ((length - index - 1) << 2));
console.log("The number after removing digit at index " + index + ": 0x" + m.toString(16));
...