繁体   English   中英

如何在不使用字符串的情况下删除 integer 数字的第 n 个十六进制数字?

[英]How to remove the nth hexadecimal digit of a integer number without using Strings?

考虑一个十六进制 integer 值,例如n = 0x12345 ,如何通过remove(n, 3) (big endian) 得到0x1235作为结果?

对于上面的输入,我认为这可以通过执行一些按位步骤来实现:

  • partA = 从索引0提取部分到targetIndex - 1 (应该返回0x123 );
  • partB = 从targetIndex + 1中提取部分到length(value) - 1 ( 0x5 );
  • 然后,结果可以表示为((partA << length(partB) | partB) ,给出0x1235结果。

但是,一旦每个十六进制数字占用 4 个空格,我仍然对如何实现它感到困惑。 另外,我不知道检索数字长度的好方法。

这可以使用字符串轻松完成,但是我需要在数千次迭代的上下文中使用它,并且不认为选择字符串是一个好主意。

那么,什么是没有字符串的删除的好方法?

解决方案:

将使用 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));
    }
}

Output:

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));
    }
}

Output:

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));

这通过编写一个从右侧移除但调整参数以从左侧移除的方法来工作。 好处是从右侧删除也可以使用。 此方法使用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

这通过递归地从末尾删除一个数字直到您要删除的那个之前的数字来工作。 然后删除它并通过调用堆栈返回,用原始值重建数字。

此方法从右数。

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是屏蔽要删除的数字的掩码。 所以从-1L (all hex 'F')和右移4*(16-offset)位开始。 这将产生一个掩码,掩码要删除的数字右侧的所有内容。 注意:如果offset0 ,则移位运算符将为64 ,并且不会移位任何位。 为了适应这一点,移位操作被分解为两个操作。

  • 现在只需屏蔽低位v & m

  • 并且高位右移4位以消除所需的数字。 (v>>>4)^ ~m
  • 然后将这两个部分简单地 OR'd 在一起。
    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);
    }

与您描述的想法类似,这可以通过为上部和下部创建一个遮罩,移动上部,然后重新组装来完成。

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 表示 32 位字中的最高十六进制数字,与输入无关,这要简单得多:

int remove(int x, int i) {
    int m = 0xffffffff >>> (4*i);
    return ((x & ~m) >>> 4) | (x & (m >>> 4));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM