Это работает, написав метод для удаления справа, но настраивая параметр для удаления слева. Бонус в том, что удаление справа также доступно для использования. Этот метод использует 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);
}