1. 大数越界问题概述

大数越界:在程序运算的过程中,变量可能超出 int32 甚至 int64 的取值范围。

解决方法:

  1. 循环取余。
  2. 快速幂取余
  3. 二分取余

1.1 循环取余

循环取余是最为简单的一种。就是在每次操作时,就对边界进行取余操作,确保结果res,是在边界内的。


把指数操作转换成一次次的乘法,每次相乘就取以此余数,使得数值不超过范围

例如:

大数取余python 大数取余数_取模

 

1.2 快速幂取余

示例

剑指 offer 16 数值的整数次方(快速幂法),这片里面讲到了如何使用快速幂。

大数取余python 大数取余数_算法_02

大数取余python 大数取余数_快速幂_03

1.2.1 例子代码

int b = n % 3, p = 1000000007;
        long rem = 1, x = 3;
        for(int a = n / 3 - 1; a > 0; a /= 2) {
            if(a % 2 == 1) rem = (rem * x) % p;
            x = (x * x) % p;
        }

计算a^n % b,其中a,b和n都是32位的整数。例如 2^31 % 3 = 2,例如 100^1000 % 1000 = 0

用快速幂的方法时间复杂度可以达到O(logn)

快速幂思想:x^2 = x * x;x^4 = x^2 * x2;x8 = x^4 * x^4……

快速幂代码

public static int fastPow(int a, int b) {
    int ans = 1;
    int base = a;
    while(b != 0) {
        if ((b & 1) != 0) {
            ans = ans * base;
        }
        base *= base;
        b >>= 1;
    }
    return ans;
}

然而这里不是简单的快速幂,还要取模.其实也挺简单,先把计算过程中的变量 ans 和 base 的数据类型改成 long ,防止数值越界,然后就是在计算乘法的时候,再加一步取模

public static int fastPow(int a, int b. int n) {
    if (n == 0) { // 规定模 0 是什么
        return 1 % b;
    }
    long ans = 1;
    long base = a;
    while(b != 0) {
        if ((b & 1) != 0) {
            ans = (ans * base) % n;
        }
        base = (base % n) * (base % n);
        b >>= 1;
    }
    return (int)ans;
}

2、%1e9+7和%1000000007的区别

很多力扣题目因为数字过大,要求答案对1000000007(1e9+7)取模,但对1e9+7取模后得到的是浮点型,有时会导致返回值无法类型转换。这时直接对1000000007取模得到int型数据即可。

3、取模公式

( a * b ) % c = [ ( a % c ) * ( b % c ) ] % c

取模运算有这样一个性质:(a+b)%c = ((a%c)+(b%c))%c
所以(pre3+pre2)%1000000007就相当于(pre3%X+pre2%X)%X
用X代替1000000007这样就使得pre3、pre2、pre3+pre2都没有溢出,之后再与pre1相加之后取模,使得全部结果没有溢出

4、为什么会对1e9+7取余?

有时候结果比较大的时候,会对结果进行mod 1e9+7操作。为什么呢?
第一:
1e9+7是一个很大的数,int32位的最大值为2147483647,所以对于int32位来说1000000007足够大。int64位的最大值为2^63-1,对于1000000007来说它的平方不会在int64中溢出所以在大数相乘的时候,因为(a∗b)%c=((a%c)∗(b%c))%c,所以相乘时两边都对1000000007取模,再保存在int64里面不会溢出 ,否则两个非常大的数在ab阶段就溢出了。有点于归一化的意思。
当一个问题只对答案的正确性有要求,而不在乎答案的数值,可能会需要将取值很大的数通过求余变小。
第二:
其次,1e9+7是一个质数,在模素数p的情况下an(a非p的倍数)的循环节长为p,这是减少冲突的一个原因。另一方面模素数p的环是无零因子环,也就是说两个非p倍数的数相乘再模p不会是零(如果是0的话,在多个数连乘的情况下会大大增加冲突概率)。比如说如果所有的结果都是偶数…你模6就只可能出现0, 2, 4这三种情况…但模5还是可以出现2, 4, 1, 3这四(4=5-1)种情况的… hash表如果是用取模的方法也要模一个大质数来减少冲突,出题人也会这样来 希望减少你“蒙对“的概率。