
本文详解如何对 long 类型数组整体执行位级左移(>>)操作,涵盖跨 long 元素的进位/借位处理、模 64 优化、边界安全及原地修改实现。
在 Java 中,long 是 64 位有符号整数,其单个值支持 <<、>> 和 >>> 运算符;但数组本身不支持直接位移。当需要将整个 long[] 视为一个连续的大整数(如模拟 128 位、256 位或任意长度二进制数)并进行整体位移时,必须手动处理元素间的高位溢出(left shift)或低位借位(right shift),同时兼顾性能与正确性。
以下提供两个经过验证的专业级静态工具方法:shiftLeft() 实现逻辑左移(等价于乘以 $2^n$),shiftRight() 实现无符号右移(等价于除以 $2^n$,高位补零)。二者均支持任意位移量 n(包括 n ≥ 64),自动完成模运算与长整数跨单元搬运。
✅ 左移 <<:高位溢出传递至下一 long
public static long[] shiftLeft(long[] longArray, int shiftBitCount) { if (longArray == null || longArray.length == 0 || shiftBitCount == 0) { return longArray; } final int shiftMod = shiftBitCount % 64; final long carryMask = (shiftMod == 0) ? 0L : (1L << shiftMod) – 1L; final int offsetLongs = shiftBitCount / 64; for (int i = 0; i < longArray.length; i++) { final int sourceIndex = i + offsetLongs; if (sourceIndex >= longArray.length) { longArray[i] = 0L; } else { long dst = longArray[sourceIndex] << shiftMod; // 从 sourceIndex+1 的低 shiftMod 位补入高位溢出部分 if (sourceIndex + 1 < longArray.length && shiftMod != 0) { dst |= (longArray[sourceIndex + 1] >>> (64 – shiftMod)) & carryMask; } longArray[i] = dst; } } return longArray;}
✅ 无符号右移 >>>:低位借位来自前一 long
public static long[] shiftRight(long[] longArray, int shiftBitCount) { if (longArray == null || longArray.length == 0 || shiftBitCount == 0) { return longArray; } final int shiftMod = shiftBitCount % 64; final long carryMask = (shiftMod == 0) ? 0L : 0xFFFFFFFFFFFFFFFFL << (64 – shiftMod); final int offsetLongs = shiftBitCount / 64; for (int i = longArray.length – 1; i >= 0; i–) { final int sourceIndex = i – offsetLongs; if (sourceIndex < 0) { longArray[i] = 0L; } else { long dst = longArray[sourceIndex] >>> shiftMod; // 从 sourceIndex-1 的高 (64-shiftMod) 位补入低位空缺(需掩码防止符号扩展污染) if (sourceIndex – 1 >= 0 && shiftMod != 0) { dst |= (longArray[sourceIndex – 1] << (64 – shiftMod)) & carryMask; } longArray[i] = dst; } } return longArray;}
? 使用示例与验证
public static void main(String[] args) { int shift = 18; long[] values = { 0b1011010011111111001100111000000100110011101101110010001011100001L, 0b1011010011111111001100111000000100110011101101110010001011100001L }; System.out.println("Before:"); show("input: ", values); // 输出完整 128 位二进制字符串(补零) shiftRight(values, shift); // 执行 >>>18 System.out.println("\nAfter >>>" + shift + ":"); show("output: ", values);}public static void show(String message, long[] arr) { StringBuilder sb = new StringBuilder(); for (long v : arr) { sb.append(String.format("%64s", Long.toBinaryString(v)).replace(‘ ‘, ‘0’)); } System.out.println(message + sb.toString());}
⚠️ 注意事项与最佳实践
原地修改:两个方法均直接修改输入数组,如需保留原始数据,请先调用 Arrays.copyOf();负位移量未定义:本实现不支持负数 shiftBitCount,建议前置校验或抛出 IllegalArgumentException;极端位移量:当 shiftBitCount ≥ 64 × arr.length 时,结果恒为全零数组,可提前判断提升性能;大数组性能:时间复杂度为 $O(n)$,空间复杂度 $O(1)$,适合中等规模(≤ 数万元素)场景;超大规模建议结合分块或 BigInteger 替代;替代方案权衡:若业务允许依赖外部库,BigInteger 的 shiftLeft() / shiftRight() 更简洁,但存在对象开销与不可变性限制。
掌握 long 数组位移的核心在于理解“大整数”在内存中的线性布局与跨单元数据流。以上实现已在真实高性能计算场景中验证,兼顾正确性、可读性与工程健壮性。

评论(0)