当前位置: 首页 > article >正文

大数取模 详解

大数取模详解

大数取模(Modular Arithmetic for Large Numbers)是计算机科学和数学中的常见问题,尤其是在密码学、数论和高效算法中广泛使用。由于大数超出常规数据类型的范围,无法直接存储或计算,因此需要采用特殊的算法和技巧来高效计算取模结果。


1. 取模运算的定义

取模运算是求两个数相除后的余数,表示为:
a m o d    m = r a \mod m = r amodm=r
其中:

  • a a a是被除数。
  • m m m是模数。
  • r r r是余数,满足 0 ≤ r < m 0 \leq r < m 0r<m

例如:
13 m o d    5 = 3 ( 因为  13 = 5 × 2 + 3 ) 13 \mod 5 = 3 \quad (\text{因为 } 13 = 5 \times 2 + 3) 13mod5=3(因为 13=5×2+3)

对于大数 a a a,直接计算 a m o d    m a \mod m amodm可能不可行,因此需要优化算法。


2. 常见场景

  1. 大整数取模

    • a a a是一个非常大的数,例如几百位甚至上千位。
    • 目标是高效计算 a m o d    m a \mod m amodm
  2. 模运算性质

    • 利用模运算的性质简化计算,例如:
      ( a + b ) m o d    m = [ ( a m o d    m ) + ( b m o d    m ) ] m o d    m (a + b) \mod m = [(a \mod m) + (b \mod m)] \mod m (a+b)modm=[(amodm)+(bmodm)]modm

      ( a × b ) m o d    m = [ ( a m o d    m ) × ( b m o d    m ) ] m o d    m (a \times b) \mod m = [(a \mod m) \times (b \mod m)] \mod m (a×b)modm=[(amodm)×(bmodm)]modm

  3. 模幂运算

    • 计算 a b m o d    m a^b \mod m abmodm,如快速幂算法。

3. 大数取模算法

(1) 基本取模方法

直接法(逐位取模)

通过逐位处理大数的每一位数字来计算取模结果。例如,对于 a = 12345678901234567890 a = 12345678901234567890 a=12345678901234567890,可以按位逐步计算 a m o d    m a \mod m amodm

计算公式:
r = ( r × 10 + d i ) m o d    m r = (r \times 10 + d_i) \mod m r=(r×10+di)modm
其中:

  • r r r是当前余数。
  • d i d_i di是数字 a a a的第 i i i位。
代码实现
public class BigNumberModulo {
    public static int bigMod(String num, int m) {
        int result = 0; // 初始余数为 0
        for (int i = 0; i < num.length(); i++) {
            int digit = num.charAt(i) - '0'; // 取当前位的数字
            result = (result * 10 + digit) % m; // 更新余数
        }
        return result;
    }

    public static void main(String[] args) {
        String num = "12345678901234567890"; // 大数作为字符串输入
        int m = 7;
        System.out.println(bigMod(num, m)); // 输出:6
    }
}
运行原理

对于大数 12345678901234567890 12345678901234567890 12345678901234567890和模数 m = 7 m = 7 m=7

  1. 从左到右逐位读取数字。
  2. 依次更新当前余数:
    • 初始 r = 0 r = 0 r=0
    • 第 1 位: r = ( 0 × 10 + 1 ) m o d    7 = 1 r = (0 \times 10 + 1) \mod 7 = 1 r=(0×10+1)mod7=1
    • 第 2 位: r = ( 1 × 10 + 2 ) m o d    7 = 5 r = (1 \times 10 + 2) \mod 7 = 5 r=(1×10+2)mod7=5
    • 以此类推,最终得出 r = 6 r = 6 r=6
时间复杂度
  • 时间复杂度为 O ( n ) O(n) O(n),其中 n n n是大数的位数。

(2) 模运算性质

性质 1:分配律

模运算满足以下分配律,可用于化简运算:

  • 加法:
    ( a + b ) m o d    m = [ ( a m o d    m ) + ( b m o d    m ) ] m o d    m (a + b) \mod m = [(a \mod m) + (b \mod m)] \mod m (a+b)modm=[(amodm)+(bmodm)]modm

  • 乘法:
    ( a × b ) m o d    m = [ ( a m o d    m ) × ( b m o d    m ) ] m o d    m (a \times b) \mod m = [(a \mod m) \times (b \mod m)] \mod m (a×b)modm=[(amodm)×(bmodm)]modm

  • 减法:
    ( a − b ) m o d    m = [ ( a m o d    m ) − ( b m o d    m ) + m ] m o d    m (a - b) \mod m = [(a \mod m) - (b \mod m) + m] \mod m (ab)modm=[(amodm)(bmodm)+m]modm

性质 2:幂运算结合律

对于幂运算:
( a b ) m o d    m = ( ( a m o d    m ) b ) m o d    m (a^b) \mod m = ((a \mod m)^b) \mod m (ab)modm=((amodm)b)modm


(3) 快速幂取模

快速幂取模算法用于高效计算 a b m o d    m a^b \mod m abmodm,通过指数的二进制分解减少运算量。

核心思想

利用:
a b m o d    m = { ( a b / 2 m o d    m ) 2 m o d    m (b 为偶数) ( a ⋅ ( a b − 1 m o d    m ) ) m o d    m (b 为奇数) a^b \mod m = \begin{cases} (a^{b/2} \mod m)^2 \mod m & \text{(b 为偶数)} \\ (a \cdot (a^{b-1} \mod m)) \mod m & \text{(b 为奇数)} \end{cases} abmodm={(ab/2modm)2modm(a(ab1modm))modm(b 为偶数)(b 为奇数)

迭代实现
public class FastExponentiation {
    public static long modularExponentiation(long a, long b, long m) {
        long result = 1;
        a = a % m; // 先取模,简化后续运算
        while (b > 0) {
            if ((b & 1) == 1) { // 如果当前指数最低位为 1
                result = (result * a) % m;
            }
            a = (a * a) % m; // 平方底数
            b >>= 1; // 指数右移一位
        }
        return result;
    }

    public static void main(String[] args) {
        System.out.println(modularExponentiation(2, 10, 1000)); // 输出:24
    }
}
运行示例

计算 2 10 m o d    1000 2^{10} \mod 1000 210mod1000

  1. 初始 a = 2 , b = 10 , m = 1000 a = 2, b = 10, m = 1000 a=2,b=10,m=1000,结果 r e s u l t = 1 result = 1 result=1
  2. b = 10 b = 10 b=10(偶数),更新 a = 4 a = 4 a=4(平方), b = 5 b = 5 b=5
  3. b = 5 b = 5 b=5(奇数),结果 r e s u l t = 1 × 4 = 4 result = 1 \times 4 = 4 result=1×4=4,更新 a = 16 a = 16 a=16 b = 2 b = 2 b=2
  4. b = 2 b = 2 b=2(偶数),更新 a = 256 a = 256 a=256 b = 1 b = 1 b=1
  5. b = 1 b = 1 b=1(奇数),结果 r e s u l t = 4 × 256 m o d    1000 = 24 result = 4 \times 256 \mod 1000 = 24 result=4×256mod1000=24

最终结果为 24 24 24

时间复杂度
  • 快速幂算法的时间复杂度为 O ( log ⁡ b ) O(\log b) O(logb)

(4) 大数与模结合

在处理大数与模运算时,常将大数分解为部分,通过逐步取模或其他分治技术避免直接计算大数。

例:大数相乘取模

如果 a a a b b b都是大数,可以用以下公式分解:
( a ⋅ b ) m o d    m = [ ( a m o d    m ) ⋅ ( b m o d    m ) ] m o d    m (a \cdot b) \mod m = [(a \mod m) \cdot (b \mod m)] \mod m (ab)modm=[(amodm)(bmodm)]modm

实现
public class BigMultiplyModulo {
    public static long multiplyMod(long a, long b, long m) {
        long result = 0;
        a %= m;
        while (b > 0) {
            if ((b & 1) == 1) { // 如果最低位为 1
                result = (result + a) % m;
            }
            a = (a << 1) % m; // 左移并模
            b >>= 1; // 右移一位
        }
        return result;
    }

    public static void main(String[] args) {
        System.out.println(multiplyMod(123456789012345678L, 987654321098765432L, 1000000007)); // 示例
    }
}

4. 应用场景

  1. 密码学
    • RSA 加密算法中需要大量模运算。
  2. 大整数运算
    • 如大数阶乘取模、斐波那契数取模。
  3. 数论
    • 解决同余方程、逆元计算。

5. 总结

算法适用场景时间复杂度
快速幂取模幂运算、大指数取模 O ( log ⁡ b ) O(\log b) O(logb)
大数相乘取模两个大数相乘后的取模 O ( log ⁡ b ) O(\log b) O(logb)
模运算分配律多次加、减、乘结合取模 O ( 1 ) O(1) O(1)(单次)

大数取模的核心思想

  1. 化整为零
    • 大数通过逐步分解(如逐位取模或逐步幂运算)解决,避免一次性直接计算。
  2. 模运算性质
    • 充分利用模运算的分配律和结合律,将复杂运算转化为小数范围内的运算。
  3. 算法优化
    • 针对幂运算和乘法,通过快速幂、逐位乘法等算法降低计算复杂度。

总结应用

大数取模是数论和密码学中的重要工具,掌握其算法和性质可以有效解决诸如大数相乘、大指数幂计算等复杂问题,同时优化程序性能。


http://www.kler.cn/a/408426.html

相关文章:

  • Linux网络——网络层
  • L14.【LeetCode笔记】返回倒数第k个节点
  • Vue.js 学习总结(14)—— Vue3 为什么推荐使用 ref 而不是 reactive
  • webStorm安装
  • 洛谷 P1722 矩阵 II C语言 记忆化搜索
  • 【贪心算法】绿洲之旅:最少次数补给探索
  • Redis除了做缓存,还能做什么???
  • 密码系统设计实验3-2
  • SQLite 管理工具 SQLiteStudio 3.4.5 发布
  • C语言中的指针和字符串的赋值
  • 3.13MayBeSomeJava that are BUTTON and listener
  • 基于网页的大语言模型聊天机器人
  • java中的最小堆
  • 深入理解 Seata:分布式事务的最佳解决方案
  • Vue.js 学习总结(15)—— 如何快速删除 node_modules 依赖文件
  • springboot实战(17)(“大事件“——新增文章主体逻辑)
  • MySQL的DELETE(删除数据)详解
  • JavaSE 总复习:夯实基础,迈向进阶之路
  • LeetCode 4.寻找两个中序数组的中位数
  • 鸿蒙进阶篇-状态管理之@Provide与@Consume
  • Linux系列-僵尸状态
  • Java基于SpringBoot+Vue的藏区特产销售平台
  • 【创建型设计模式】单例模式
  • flink学习(1)——standalone模式的安装
  • GMAN解读(论文+代码)
  • 【面向对象】Java处理异常的方式