取模相关操作的Java代码实现

模加与模乘

/**
 * 模加
 *
 * @param x
 * @param y
 * @return (x + y) % mod
 */
public static long add(long x, long y, long mod) {
    return ((x % mod) + (y % mod)) % mod;
}
/**
 * 模乘
 *
 * @param x
 * @param y
 * @return x * y % mod
 */
public static long mul(long x, long y, long mod) {
    return ((x % mod) * (y % mod)) % mod;
}

模快速幂算法

先说一下快速幂,快速幂用于快速得出一个整数的整数幂次的值,如下图所示
快速幂过程
模快速幂,即在快速幂的基础上,每一部加上取模操作。
模快速幂代码如下,如不需要取模操作,只要将代码中取模操作相关的代码去掉即可。
这里的代码实现通过递归实现,迭代的实现方式这里不再展示。

/**
 * 模快速幂
 *
 * @param x
 * @param n
 * @return x^n % mod
 */
public static long quickPower(long x, long n, long mod) {
    if (n == 0) return 1;
    if (n == 1) return x % mod;
    long tmp = quickPower(x, n >> 1, mod);
    // mul方法即为上面的模乘
    return (n & 1) == 0 ? mul(tmp, tmp, mod) : mul(x, mul(tmp, tmp, mod), mod);
}

费马小定理求解分数的模

费马小定理:a^(p-1) mod p = 1 mod p
费马小定理使用的前提是p为素数,否则结果不正确。

比如求(b/a) % p

由费马小定理:
a^(p-1) mod p = 1 mod p
a * a^(p-2) mod p = 1 mod p
a^(p-2) mod p = a^(-1) mod p
(b/a) % p = b * a^(-1) % p = b * a^(p-2) % p

代码实现如下

/**
 * 分数求模
 * 费马小定理(前提是模是素数)
 * a^(p-1) mod p = 1 mod p
 * a * a^(p-2) mod p = 1 mod p
 * a^(p-2) mod p = a^(-1) mod p
 * (b/a) % p = b * a^(-1) % p = b * a^(p-2) % p
 *
 * @param a 分母
 * @param b 分子
 * @return (b / a) % mod
 */
public static long fractionMod(long a, long b, long mod) {
	// 这里使用上面的模快速幂的方法
    return mul(b, quickPower(a, mod - 2, mod), mod);
}

欧几里得算法(求最大公约数)

欧几里得算法,又名辗转相除法,具体原理这里不再说明

/**
 * 欧几里得算法
 * 获取两个整数的最大公约数
 *
 * @param a
 * @param b
 * @return
 */
public static int gcd(int a, int b) {
    if (b == 0) {
        return a;
    } else {
        return gcd(b, a % b);
    }
}

扩展欧几里得算法(求最大公约数的同时获取ax + by = gcd(a, b)的一组解)

/**
 * 扩展欧几里得算法
 * 获取 ax + by = gcd(a, b)的一组解,且返回 a,b 的最大公约数
 *
 * @param a
 * @param b
 * @param variable 保存变量x, y,你也可以通过别的方式操作
 * @return a, b 的最大公约数
 */
public static int exGcd(int a, int b, IntegerVariable variable) {
    if (b == 0) {
        variable.x = 1;
        variable.y = 0;
        return a;
    }
    int g = exGcd(b, a % b, variable);
    int temp = variable.x;
    variable.x = variable.y;
    variable.y = temp - (a / b) * variable.y;
    return g;
}
// 用于保存x与y的值,你也可以通过别的方式操作
public static class IntegerVariable {
    int x;
    int y;
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    @Override
    public String toString() {
        return "IntegerVariable{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

求乘法逆元

乘法逆元的这里不再赘述,直接上代码

/**
 * 求 a 模 m 的乘法逆元
 *
 * @param a
 * @param m
 * @return
 */
public static int inverse(int a, int m) {
    IntegerVariable variable = new IntegerVariable();
    int g = exGcd(a, m, variable);
    return (variable.x % m + m) % m; //如果variable.x为负数,这里变为正数
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值