位运算

位运算是直接对整数的二进制位进行操作的运算

常见的位运算有:

  1. 与运算(AND)&
    • 对应位都为 1 时结果为 1,否则为 0。
  2. 或运算(OR)|
    • 对应位有 1 时结果为 1,否则为 0。
  3. 异或运算(XOR)^
    • 对应位不同为 1,相同为 0。
  4. 取反运算(NOT)~
    • 逐位取反(0 变 1,1 变 0)。
  5. 左移运算(左移)<<
    • 将位向左移动指定的位数,低位补 0。
  6. 右移运算(右移)>>
    • 将位向右移动指定的位数,高位填充符号位(对于无符号数,高位补 0)。

简单介绍六种位运算

与运算(AND)

// C语言
#include <stdio.h>

int main() {
    int a = 5;  // 二进制 0101
    int b = 3;  // 二进制 0011
    printf("%d\n", a & b);  // 结果为 1(二进制 0001)
    return 0;
}

// Java
public class Main {
    public static void main(String[] args) {
        int a = 5;  // 二进制 0101
        int b = 3;  // 二进制 0011
        System.out.println(a & b);  // 输出 1(二进制 0001)
    }
}

或运算(OR)

// C语言
#include <stdio.h>

int main() {
    int a = 5;  // 二进制 0101
    int b = 3;  // 二进制 0011
    printf("%d\n", a | b);  // 结果为 7(二进制 0111)
    return 0;
}
// Java
public class Main {
    public static void main(String[] args) {
        int a = 5;  // 二进制 0101
        int b = 3;  // 二进制 0011
        System.out.println(a | b);  // 输出 7(二进制 0111)
    }
}

异或运算(XOR)

// C语言
#include <stdio.h>

int main() {
    int a = 5;  // 二进制 0101
    int b = 3;  // 二进制 0011
    printf("%d\n", a ^ b);  // 结果为 6(二进制 0110)
    return 0;
}
// Java
public class Main {
    public static void main(String[] args) {
        int a = 5;  // 二进制 0101
        int b = 3;  // 二进制 0011
        System.out.println(a ^ b);  // 输出 6(二进制 0110)
    }
}

取反运算(NOT)

// C语言
#include <stdio.h>

int main() {
    int a = 5;  // 二进制 0101
    printf("%d\n", ~a);  // 结果为 -6(取反后变为二进制 1010)
    return 0;
}
// Java
public class Main {
    public static void main(String[] args) {
        int a = 5;  // 二进制 0101
        System.out.println(~a);  // 输出 -6(取反后变为二进制 1010)
    }
}

左移运算 <<

// C语言
#include <stdio.h>

int main() {
    int a = 5;  // 二进制 0101
    printf("%d\n", a << 1);  // 结果为 10(二进制 1010),左移 1 位
    return 0;
}
// Java
public class Main {
    public static void main(String[] args) {
        int a = 5;  // 二进制 0101
        System.out.println(a << 1);  // 输出 10(二进制 1010)
    }
}

右移运算 >>

// C语言
#include <stdio.h>

int main() {
    int a = 5;  // 二进制 0101
    printf("%d\n", a >> 1);  // 结果为 2(二进制 0010),右移 1 位
    return 0;
}
// Java
public class Main {
    public static void main(String[] args) {
        int a = 5;  // 二进制 0101
        System.out.println(a >> 1);  // 输出 2(二进制 0010)
    }
}

常见运用

1.检查一个数是否是2的幂

判断一个数是否是 2 的幂(即 1, 2, 4, 8, 16, ...)。

原理

  • 一个数是 2 的幂时,它的二进制表示中只有一个 1,比如:

    • 1 的二进制是 0001
    • 2 的二进制是 0010
    • 4 的二进制是 0100
    • 8 的二进制是 1000

    2 的幂数的特点是:n & (n - 1) == 0,这个条件成立时,n 就是 2 的幂。

// C语言
#include <stdio.h>

int isPowerOfTwo(int n) {
    return (n > 0) && (n & (n - 1)) == 0;
}

int main() {
    int n = 16;
    if (isPowerOfTwo(n)) {
        printf("%d is a power of 2\n", n);
    } else {
        printf("%d is not a power of 2\n", n);
    }
    return 0;
}
// Java
public class Main {
    public static boolean isPowerOfTwo(int n) {
        return (n > 0) && (n & (n - 1)) == 0;
    }

    public static void main(String[] args) {
        int n = 16;
        if (isPowerOfTwo(n)) {
            System.out.println(n + " is a power of 2");
        } else {
            System.out.println(n + " is not a power of 2");
        }
    }
}

2.交换两个数

使用异或运算可以实现两个数的交换,避免使用临时变量。

原理

  • 利用异或的性质:a = a ^ b, b = a ^ b, a = a ^ b,实现 ab 的交换。
    • a ^ b 相当于两个数的“差”,再通过这种“差”运算恢复原数值。
// C语言
#include <stdio.h>

void swap(int* a, int* b) {
    *a = *a ^ *b;
    *b = *a ^ *b;
    *a = *a ^ *b;
}

int main() {
    int a = 5, b = 10;
    printf("Before swap: a = %d, b = %d\n", a, b);
    swap(&a, &b);
    printf("After swap: a = %d, b = %d\n", a, b);
    return 0;
}
// Java
public class Main {
    public static void swap(int[] a, int[] b) {
        a[0] = a[0] ^ b[0];
        b[0] = a[0] ^ b[0];
        a[0] = a[0] ^ b[0];
    }

    public static void main(String[] args) {
        int a = 5, b = 10;
        System.out.println("Before swap: a = " + a + ", b = " + b);
        swap(new int[]{a}, new int[]{b});
        System.out.println("After swap: a = " + a + ", b = " + b);
    }
}

3.求一个整数二进制表示中 1 的个数(汉明重量)

使用位运算可以高效地计算一个整数的二进制中有多少个 1,常用于计算二进制中某个数的位数。

原理

  • 每次 n & (n - 1) 可以消除一个 1,直到 n 为 0。这个方法的时间复杂度为 O(log n)
// C语言
#include <stdio.h>

int hammingWeight(int n) {
    int count = 0;
    while (n) {
        count++;
        n = n & (n - 1);  // 每次消去最低位的 1
    }
    return count;
}

int main() {
    int n = 29;  // 二进制 11101
    printf("Hamming weight: %d\n", hammingWeight(n));  // 输出 4
    return 0;
}
// Java
public class Main {
    public static int hammingWeight(int n) {
        int count = 0;
        while (n != 0) {
            count++;
            n = n & (n - 1);  // 每次消去最低位的 1
        }
        return count;
    }

    public static void main(String[] args) {
        int n = 29;  // 二进制 11101
        System.out.println("Hamming weight: " + hammingWeight(n));  // 输出 4
    }
}

4.找出整数数组中的唯一数字(每个数字出现两次,只有一个数字出现一次)

假设在一个数组中,除了一个数字,其余的数字都出现了两次,使用位运算可以高效地找出唯一的数字。

原理

  • 使用异或运算的性质:相同的数字异或为 0,不同的数字异或为非 0。最终,数组中的唯一数字将保留下来。
// C语言
#include <stdio.h>

int singleNumber(int* nums, int numsSize) {
    int result = 0;
    for (int i = 0; i < numsSize; i++) {
        result ^= nums[i];  // 相同数字会被消除,剩下唯一的数字
    }
    return result;
}

int main() {
    int nums[] = {4, 1, 2, 1, 2};
    int size = sizeof(nums) / sizeof(nums[0]);
    printf("Single number: %d\n", singleNumber(nums, size));  // 输出 4
    return 0;
}
// Java
public class Main {
    public static int singleNumber(int[] nums) {
        int result = 0;
        for (int num : nums) {
            result ^= num;  // 相同数字会被消除,剩下唯一的数字
        }
        return result;
    }

    public static void main(String[] args) {
        int[] nums = {4, 1, 2, 1, 2};
        System.out.println("Single number: " + singleNumber(nums));  // 输出 4
    }
}

5. 交换整数的偶数位和奇数位

将一个整数的偶数位和奇数位互换,可以通过位运算来实现。

原理

  • 使用掩码分离出偶数位和奇数位,然后将它们左移或右移并组合起来。
// C语言
#include <stdio.h>

unsigned int swapEvenOddBits(unsigned int n) {
    unsigned int evenBits = n & 0xAAAAAAAA;  // 获取偶数位
    unsigned int oddBits = n & 0x55555555;   // 获取奇数位
    evenBits >>= 1;  // 偶数位右移
    oddBits <<= 1;   // 奇数位左移
    return (evenBits | oddBits);
}

int main() {
    unsigned int n = 23;  // 二进制 10111
    printf("After swapping bits: %u\n", swapEvenOddBits(n));  // 输出 43(二进制 101011)
    return 0;
}
// Java
public class Main {
    public static int swapEvenOddBits(int n) {
        int evenBits = n & 0xAAAAAAAA;  // 获取偶数位
        int oddBits = n & 0x55555555;   // 获取奇数位
        evenBits >>= 1;  // 偶数位右移
        oddBits <<= 1;   // 奇数位左移
        return (evenBits | oddBits);
    }

    public static void main(String[] args) {
        int n = 23;  // 二进制 10111
        System.out.println("After swapping bits: " + swapEvenOddBits(n));  // 输出 43(二进制 101011)
    }
}

6. 判断一个数是否是奇数或偶数

位运算可以非常高效地判断一个整数是奇数还是偶数。

原理

  • 一个整数的二进制表示的最后一位(最低位)决定了该数是奇数还是偶数:

    • 如果最低位为 1,则该数为奇数。
    • 如果最低位为 0,则该数为偶数。

    通过与操作 n & 1,如果结果是 1,则是奇数;如果结果是 0,则是偶数。

// C语言
#include <stdio.h>

int isEven(int n) {
    return (n & 1) == 0;
}

int main() {
    int n = 7;
    if (isEven(n)) {
        printf("%d is even\n", n);
    } else {
        printf("%d is odd\n", n);
    }
    return 0;
}
// Java
public class Main {
    public static boolean isEven(int n) {
        return (n & 1) == 0;
    }

    public static void main(String[] args) {
        int n = 7;
        if (isEven(n)) {
            System.out.println(n + " is even");
        } else {
            System.out.println(n + " is odd");
        }
    }
}

7. 清除最低有效位(Lowest Set Bit)

有时你需要删除一个整数中的最低有效位(第一个 1),可以通过位运算实现。

原理

  • n & (n - 1) 可以清除最低有效位。例如:
    • 对于 n = 12(二进制 1100),n - 1 = 11(二进制 1011),n & (n - 1) 就是 1000,清除了最低有效位。
// C语言
#include <stdio.h>

int clearLowestBit(int n) {
    return n & (n - 1);
}

int main() {
    int n = 12;  // 二进制 1100
    printf("After clearing the lowest bit: %d\n", clearLowestBit(n));  // 输出 8(二进制 1000)
    return 0;
}
// Java
public class Main {
    public static int clearLowestBit(int n) {
        return n & (n - 1);
    }

    public static void main(String[] args) {
        int n = 12;  // 二进制 1100
        System.out.println("After clearing the lowest bit: " + clearLowestBit(n));  // 输出 8(二进制 1000)
    }
}

8. 交换整数的符号

通过位运算,你可以改变一个整数的符号(即负数变为正数,正数变为负数)。

原理

  • 通过异或操作,可以反转整数的符号位(最高位)。例如:n = n ^ (1 << 31),这会将 n 的符号位取反。
// C语言
#include <stdio.h>

int swapSign(int n) {
    return n ^ (1 << 31);  // 将符号位取反
}

int main() {
    int n = -5;
    printf("After swapping sign: %d\n", swapSign(n));  // 输出 5
    return 0;
}
// Java
public class Main {
    public static int swapSign(int n) {
        return n ^ (1 << 31);  // 将符号位取反
    }

    public static void main(String[] args) {
        int n = -5;
        System.out.println("After swapping sign: " + swapSign(n));  // 输出 5
    }
}

9. 求两个数的最大公约数(GCD)

可以利用位运算快速求解两个数的最大公约数(Euclid's algorithm),特别是在处理大数时,位运算可以提高效率。

原理

  • 利用二进制求最大公约数的方法,可以通过 n & -n 来去除数字的最低有效位,从而加速求 GCD。
// C语言
#include <stdio.h>

int gcd(int a, int b) {
    if (a == 0) return b;
    if (b == 0) return a;
    int shift;
    
    // 计算 a 和 b 的二进制表示中公共的 2 的幂
    for (shift = 0; ((a | b) & 1) == 0; ++shift) {
        a >>= 1;
        b >>= 1;
    }
    
    while ((a & 1) == 0) a >>= 1;  // 去除 a 中的所有 2 的幂
    
    do {
        while ((b & 1) == 0) b >>= 1;  // 去除 b 中的所有 2 的幂
        if (a > b) {
            int temp = a;
            a = b;
            b = temp;
        }
        b = b - a;  // b = b - a
    } while (b != 0);
    
    return a << shift;  // 将公共的 2 的幂加回来
}

int main() {
    int a = 56, b = 98;
    printf("GCD of %d and %d is: %d\n", a, b, gcd(a, b));  // 输出 GCD
    return 0;
}
// Java
public class Main {
    public static int gcd(int a, int b) {
        if (a == 0) return b;
        if (b == 0) return a;
        int shift = 0;
        
        // 计算 a 和 b 的二进制表示中公共的 2 的幂
        while ((a | b) % 2 == 0) {
            a >>= 1;
            b >>= 1;
            shift++;
        }
        
        while ((a & 1) == 0) a >>= 1;  // 去除 a 中的所有 2 的幂
        
        do {
            while ((b & 1) == 0) b >>= 1;  // 去除 b 中的所有 2 的幂
            if (a > b) {
                int temp = a;
                a = b;
                b = temp;
            }
            b = b - a;  // b = b - a
        } while (b != 0);
        
        return a << shift;  // 将公共的 2 的幂加回来
    }

    public static void main(String[] args) {
        int a = 56, b = 98;
        System.out.println("GCD of " + a + " and " + b + " is: " + gcd(a, b));
    }
}

10. 通过位运算判断两个整数是否相等

如果两个整数相等,则它们的异或结果为 0。这可以通过 a ^ b 来判断两个数是否相等。

原理

  • 如果 ab 相等,a ^ b == 0
// C语言
#include <stdio.h>

int areEqual(int a, int b) {
    return (a ^ b) == 0;  // 如果 a 和 b 相等,则 a ^ b 为 0
}

int main() {
    int a = 5, b = 5;
    if (areEqual(a, b)) {
        printf("%d and %d are equal\n", a, b);
    } else {
        printf("%d and %d are not equal\n", a, b);
    }
    return 0;
}
// Java
public class Main {
    public static boolean areEqual(int a, int b) {
        return (a ^ b) == 0;  // 如果 a 和 b 相等,则 a ^ b 为 0
    }

    public static void main(String[] args) {
        int a = 5, b = 5;
        if (areEqual(a, b)) {
            System.out.println(a + " and " + b + " are equal");
        } else {
            System.out.println(a + " and " + b + " are not equal");
        }
    }
}

java与c的位运算区别

在 Java 和 C 中,位运算的基本原理和操作是相同的,但它们在一些细节上有所不同,

主要体现在 数据类型的处理符号扩展溢出处理 等方面。

1. 数据类型和位宽

  • C 语言
    • C 语言中的整数类型如 intshortlong 等的位宽是由平台和编译器决定的。通常,int 在大多数平台上是 32 位,long 可能是 32 位或 64 位。
    • C 语言对有符号类型的位运算有时会产生未定义行为,尤其是在符号扩展时。
    • C 语言的类型也允许使用 char(通常是 8 位)进行位运算。
  • Java
    • 在 Java 中,intlong固定长度 的。int 总是 32 位,long 总是 64 位。
    • Java 中的所有整数类型(包括 byte, short, int, long)的位运算操作都将其转换为 32 位或 64 位的二进制表示。
    • Java 不允许直接操作 char 类型的位(char 在 Java 中是 16 位无符号类型,不能进行位运算),但是可以通过 int 类型来实现相同的操作。

2. 符号扩展

  • C 语言

    • C 语言中进行右移操作时,有符号整数 右移会进行符号扩展,即将符号位(最高位)填充到左边。这意味着对于负数,右移后会填充 1,对于正数,右移后会填充 0
    • 对于 无符号整数,右移不会进行符号扩展,而是填充 0

    例如:

    int a = -8;  // 二进制:11111111111111111111111111111000
    printf("%d\n", a >> 2);  // 输出 -2,二进制:11111111111111111111111111111110
    
  • Java

    • Java 中的 有符号整数 右移也会进行符号扩展,但是 Java 提供了两种不同的右移操作:
      • 算术右移(>>:进行符号扩展。
      • 逻辑右移(>>>:无论是有符号还是无符号整数,都会填充 0
    • Java 对于无符号整数的处理不同于 C,因为 Java 中的整数是 有符号 的,char 不是无符号类型,因此不能直接进行无符号右移。但可以通过 >>> 来实现无符号右移。

    例如:

    int a = -8;  // 二进制:11111111111111111111111111111000
    System.out.println(a >> 2);   // 输出 -2,二进制:11111111111111111111111111111110
    System.out.println(a >>> 2);  // 输出 1073741822,二进制:00111111111111111111111111111110
    

3. 溢出处理

  • C 语言

    • C 语言中的 溢出行为 是未定义的,特别是对于有符号整数。对有符号整数进行溢出(例如,int 超过其最大值或最小值)会导致未定义的行为,而对无符号整数进行溢出则会发生 模运算,即会“环绕”回 0。

    例如:

    int a = 2147483647;  // int 类型最大值
    a = a + 1;  // 会发生溢出,结果未定义
    printf("%d\n", a);
    
  • Java

    • 在 Java 中,溢出是定义好的行为。对于 有符号整数,如果超出 intlong 的范围,结果会回绕到最小值。例如,int 的最大值是 2147483647,当其值超过该范围时,会回绕到负数。Java 中的 整数溢出 是通过 模运算 实现的。

    例如:

    int a = 2147483647;  // int 类型最大值
    a = a + 1;  // 溢出,结果是 -2147483648
    System.out.println(a);  // 输出 -2147483648
    

4. 位运算优先级

  • C 语言

    • 在 C 语言中,位运算的优先级低于大多数算术运算,因此如果要确保位运算优先执行,通常需要使用括号。

    例如:

    int result = 5 + 3 << 2;  // 先执行加法,再执行左移
    
  • Java

    • Java 中的位运算优先级和 C 类似,但有时在与其他运算符结合时需要小心。例如,Java 中的位运算同样优先级较低,需要使用括号明确运算顺序。

    例如:

    int result = 5 + 3 << 2;  // 先执行加法,再执行左移
    

5. 有符号与无符号类型

  • C 语言

    • C 语言中可以使用 无符号类型(如 unsigned intunsigned char),并且对无符号整数的位运算不会涉及符号扩展。

    例如:

    unsigned int a = 4294967295;  // 最大无符号整数值
    printf("%u\n", a + 1);  // 输出 0(无符号溢出)
    
  • Java

    • Java 中的整数类型都是 有符号 的,因此没有 unsigned intunsigned long 类型。Java 提供了 >>>(逻辑右移)来模拟无符号整数的操作,但并没有专门的无符号类型。在 Java 中处理无符号整数需要特别小心,通常需要通过 long 类型来处理更大的数值范围。

    例如

    int a = -1;
    System.out.println(a >>> 1);  // 输出 2147483647(无符号右移)
    

6. 溢出与取模

  • C 语言
    • C 中对无符号整数的溢出会发生取模操作,而对有符号整数则会产生未定义行为。
  • Java
    • 在 Java 中,溢出操作是严格定义的,对于整数溢出,会按照二进制取模操作进行。

总结

  • 位运算的核心操作(与、或、非、异或、左移、右移)在 C 和 Java 中的基本原理相同,但由于两者对整数类型的处理有所不同,特别是在符号扩展、溢出行为和无符号类型支持上有所差异。
  • Java 语言提供了更为严格和一致的行为(如固定位宽、符号扩展等),但是也限制了对无符号类型的直接支持;而 C 语言则具有更大的灵活性,尤其是在平台相关的类型宽度和未定义行为方面,开发者需要更小心地处理溢出和符号扩展等问题。

溢出与取模

溢出(Overflow)和取模(Modulo)是位运算和数学运算中非常重要的概念,特别是在处理整数类型时。溢出与取模的关系在不同的编程语言和不同的数值类型下会有不同的表现。

1. 溢出 (Overflow)

溢出通常是指一个数值超出了其数据类型所能表示的范围。溢出可能会导致结果变为未定义,或者是某种“环绕”行为(即从最大值回到最小值或反之)。溢出经常出现在整数计算中,特别是在加法、乘法等运算中,或者在右移、左移等位运算中。

溢出的类型:

  • 有符号溢出:当对 有符号整数 进行运算时,如果计算结果超出了该类型的表示范围,就会发生溢出。
  • 无符号溢出:对于 无符号整数,溢出通常是以 模运算 的方式处理,即结果回绕到类型的最小值(0)处。

有符号溢出的例子:

在有符号整数的运算中,如果一个值超过了该类型的最大值,通常会导致溢出,并且在 C 语言 中,溢出的行为是未定义的,可能会导致不可预期的结果。

C 语言中的溢出示例

#include <stdio.h>

int main() {
    int max = 2147483647;  // 32-bit int 类型的最大值
    printf("%d\n", max + 1);  // 溢出,结果未定义
    return 0;
}

在上述代码中,max + 1 的结果会超出 int 类型的最大值,这会导致溢出,结果是未定义的,可能会表现为负数或某个非常不正常的数值。

Java 中的溢出:

Java 中,溢出是有定义的。对于 有符号整数(如 int),如果计算超出了该类型的表示范围,结果会回绕。例如,int 的最大值是 2147483647,再加 1 就会回绕到最小值 -2147483648

Java 中的溢出示例

public class Main {
    public static void main(String[] args) {
        int max = 2147483647;  // int 类型的最大值
        System.out.println(max + 1);  // 输出 -2147483648,发生溢出
    }
}

在 Java 中,溢出的结果是 环绕 的,结果会回到整数类型的最小值。

2. 溢出与取模

溢出和取模之间的关系主要体现在整数运算中,尤其是在处理无符号整数时。具体来说,当无符号整数超出其最大值时,运算会按 模运算 规则处理,即回绕到零或最小值。

无符号溢出的模运算:

对于 无符号整数,溢出是通过模运算来处理的。无符号整数的溢出会回绕到零或最小值,而不是出现未定义行为。例如,假设有一个 8 位无符号整数,其最大值为 255。如果我们将其值加 1,就会回绕到 0。

C 语言中的无符号溢出示例

#include <stdio.h>

int main() {
    unsigned int max = 4294967295;  // 32-bit unsigned int 的最大值
    printf("%u\n", max + 1);  // 输出 0,无符号溢出(模运算)
    return 0;
}

在这个例子中,max + 1 超出了 unsigned int 能表示的最大值 4294967295,因此会发生 模运算,回绕到 0

溢出与取模的本质:

  • 对于 无符号整数,每当一个值超出其能表示的最大值时,它会像一个环绕计数器一样,从最大值回到最小值。这个过程可以通过取模运算来描述。
    • 对于一个无符号 n 位整数,n 的最大值是 2^n - 1。当数值超过这个最大值时,它会回绕并重新开始计算。
    • 例如,对于一个 8 位无符号整数(最大值 255),计算 256 % 256 会得到 0。

3. 右移和溢出

在位运算中,右移操作常常会导致溢出,尤其是对于有符号整数。右移会将最低有效位(最右边的位)丢弃,并且根据类型的符号位决定填充的位(符号扩展或零扩展)。

C 语言的右移溢出:

对于有符号整数,右移操作会导致符号扩展(即用符号位填充空位),但如果是无符号整数,右移则会填充零。

C 语言中的右移示例

#include <stdio.h>

int main() {
    int a = -8;  // 二进制:11111111111111111111111111111000
    printf("%d\n", a >> 2);  // 输出 -2,符号扩展
    return 0;
}

对于有符号整数,右移时,会用符号位填充空位,导致 -8 右移后变成 -2

Java 的右移与溢出:

在 Java 中,右移的行为和 C 类似,但 Java 提供了两种右移操作:

  • 算术右移(>>:会进行符号扩展。
  • 逻辑右移(>>>:会用 0 填充空位,即无符号右移。

Java 中的右移示例

public class Main {
    public static void main(String[] args) {
        int a = -8;  // 二进制:11111111111111111111111111111000
        System.out.println(a >> 2);   // 输出 -2,符号扩展
        System.out.println(a >>> 2);  // 输出 1073741822,无符号右移
    }
}

在上面的例子中,>> 做的是算术右移,>>> 做的是逻辑右移,后者无论符号如何,都会用零填充空位。

4. 溢出与取模在实际应用中的应用

  • 哈希算法:在哈希算法中,溢出和取模是常见的操作。通常,哈希函数会返回一个数值,然后使用取模运算(如 hash % table_size)来确定数据存储的索引。这个过程实际上是在使用模运算处理溢出,确保索引值在有效范围内。
  • 计数器与环绕:在一些计数器或者循环中,溢出和取模通常是用来实现循环行为的。例如,计数器在达到了最大值后会从 0 开始。
  • 无符号整数的应用:在处理非常大的数值时,尤其是在 图形处理网络协议 中,经常会使用无符号整数,这时溢出和模运算就显得尤为重要。