【问题标题】:Java BigInteger , number theory , modular arithmetic [closed]Java BigInteger,数论,模算术[关闭]
【发布时间】:2014-12-19 01:26:49
【问题描述】:

有人知道如何在java中实现这样的问题吗?

"实现一个子程序,它接受三个正整数参数 (a; b; n) 并返回 ((a 的 b 次方) mod n) 的值,其中参数由大约 100 个十进制数字表示。使用四种不同的方法。”

提前致谢

UPD:方法如下

M1)

public BigInteger Result1(BigInteger a , BigInteger b , BigInteger n){
    BigInteger Res = new BigInteger("1");
    for (BigInteger i = new BigInteger("0"); !i.equals(b); i = i.add(new BigInteger("1"))) {
        Res = Res.multiply(a).mod(n);
    }
    return Res;
}

M2)

public BigInteger Result2(BigInteger a , BigInteger b , BigInteger n){
    BigInteger Res = new BigInteger("1");
    for (BigInteger i = new BigInteger("0"); !i.equals(b); i = i.add(new BigInteger("1"))) {
        Res = Res.multiply(a);
    }
    return Res.mod(n);
}

M3)

ublic BigInteger Result3(BigInteger a , BigInteger b , BigInteger n){
    if(b.equals(new BigInteger("0"))){
        return new BigInteger("1");
    }
    else if(b.mod(new BigInteger("2")).equals(new BigInteger("0"))){
        BigInteger Res = Result3(a,b.divide(new BigInteger("2")),n);
        return (Res.multiply(Res)).mod(n);
    }
    else{
        return ( (a.mod(n)).multiply(Result3(a, b.subtract(new BigInteger("1")), n)) ).mod(n);
    }
}

M4)

public BigInteger Result4(BigInteger a , BigInteger b , BigInteger n){
    BigInteger Res = new BigInteger("1");
    while(!b.equals(new BigInteger("0"))) {
        if(!(b.mod(new BigInteger("2"))).equals(new BigInteger("0"))) {
            Res = Res.multiply(a).mod(n);
        }
        a = a.multiply(a).mod(n);
        b = b.divide(new BigInteger("2"));
    }
    return Res;
}

【问题讨论】:

  • 向我们展示您的尝试。
  • @pbabcdefp 关于 (a to the power b) 部分,我尝试了以下代码 sn-p pastebin.com/McVawk6W 但不幸的是,该项目没有任何输出就终止了。

标签: java biginteger number-theory modular-arithmetic


【解决方案1】:

要直接回答您的问题, 我认为BigInteger.modPow 可能是您正在寻找的。

public BigInteger modPow(BigInteger exponent,
                     BigInteger m)

返回一个 BigInteger,其值为 (this^exponent mod m)

或者(并且更有效),您还可以将 (a mod n) 提高到 (b mod n) 的幂,这应该会使代码运行得更快。

(a^b mod n) = ((a mod n)^(b mod n) mod n)

【讨论】:

  • (a^b mod n) 与 ((a mod n)^(b mod n) mod n) 不同。如果 a=2,b=5,n=3,则第一个为 2,而第二个为 1。
  • @pbabcdefp 如果您知道的话,您通常可以以乘法组的阶数为模减少指数,即 totient(n)。但是对于公钥加密,这是大整数 modexp 的唯一常见的现实世界应用,选择数字使得 a 已经是 mod n 并且 b 已经是 mod totient(n)。
  • @dave_thompson_085 只有当基模 n 实际上是乘法群的一个元素时才能减少它,但它可能不是。例如,如果 n = 4,则乘法组的阶数为 2。但如果计算出 2 ^ 2 mod 4,则得到 0。将幂减 2 得到 2 ^ 0 = 1 mod 4。我知道我的数理论!
【解决方案2】:

惊慌失措,这被搁置了......

为了理论,如果您想编写自己的自定义方法,请根据数学技巧检查以下内容,以避免计算。首先是解决方案,然后是其背后的数学。

您的子程序可能如下所示:

public static BigInteger customPowMod(BigInteger a, BigInteger b, BigInteger n){
    BigInteger previous = a.mod(n);
    BigInteger runningTotal = new BigInteger("1");
    for(int i = 0; i < a.bitLength(); i++){
        if(a.testBit(i)){
            runningTotal = runningTotal.multiply(previous);
        }
        previous = previous.multiply(previous).mod(n);
    }
    return runningTotal.mod(n);
}

以下是如何调用该方法的示例:

public static void main(String[] args) {
    BigInteger a = new BigInteger("1700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005");
    BigInteger b = new BigInteger("6300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005");
    BigInteger n = new BigInteger("50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
    //note the following produce the same values
    System.out.println(customPowMod(a,b,n)); 
    System.out.println(a.modPow(b,n));
}

现在解释一下

为了说明问题,我正在做一些较小的数字……最终将 get 转换为代码的是手工过程。

  • a = 17
  • b = 63
  • n = 5

首先你想看看你的幂数b是由什么base2组成的。例如:

63 = 2^5 + 2^4 + 2^3 + 2^2 + 2^1 + 2^0 = 32 + 16 + 8 + 4 + 2 + 1。

或二进制11111

这可以通过从 0 迭代到我们的 BigInteger b 的.bitLength() 并使用.testBit() 检查给定位来以编程方式找到。 因此 Java 代码中的 for 循环。

接下来我们会找到您的基本模数 (n) 目标的倍数(您的价值需要与前一段中的 2 的最高幂一样远):

让我们将每个简化值称为a&lt;power_of_2&gt;

  • 一个 mod n = a1
  • a^2 mod n = a2
  • a^4 mod n = (a2)^2 mod n = a4 mod n
  • a^8 mod n = (a4)^2 mod n = a8 mod n
  • ...

以及手动值:

  • 17^1 % 5 = 2
  • 17^2 % 5 = 2^2 mod 5 = 4 mod 5 = 4
  • 17^4 % 5 = 4^2 mod 5 = 16 mod 5 = 1
  • 17^8 % 5 = 1^2 mod 5 = 1 mod 5 = 1
  • 17^16 % 5 = 1^2 mod 5 = 1 mod 5 = 1
  • 17^32 % 5 = 1^2 mod 5 = 1 mod 5 = 1

有问题的是,这可以与上一步查找 base2 幂同步完成,每次迭代您还可以找到最新的a&lt;power_of_2&gt;在我们达到最大值之前,需要计算每个额外的平方,因此循环中的 previous 值会不断增加。

最后,我们取必要的 a 值并将它们相乘,然后是 n 的模数。 这是在 for 循环的 if 语句中。

  • 同样,我们拥有以下权力:32 + 16 + 8 + 4 + 2 + 1

从上面的步骤中,我们得到了值并将它们相乘(后面是循环结束时的模数):

1 * 1 * 1 * 1 * 4 * 2 % 5 = 8 % 5 = 3

【讨论】:

    【解决方案3】:

    如果您不是非常需要性能,您可以为此使用BigInteger 类。 BigInteger 是不可变的。

    public static BigInteger getValue(int a, int b, int n) {
        return BigInteger.valueOf(a).modPow(BigInteger.valueOf(b), BigInteger.valueOf(n));
    }
    

    【讨论】:

    • 非常低效 - 正确答案是关于实际需要计算什么的 CS/数学技巧。
    • @GabeSechan 我不明白这是一个“错误的答案”。他没有说他的其他要求。
    • @GabeSechan 你显然没有看过BigInteger.modPow()的实现
    • @GabeSechan 考虑到他用 BigInteger 标记了这个问题,这似乎就是他所要求的。但也许我读错了,应该直接“永久退出这个领域”。
    • 好吧,一方面你的答案是错误的——他说 b 和 n 可以有数百个数字,而你将它们作为整数传递。另一个人更正确地回答了 modPow。
    猜你喜欢
    • 2012-11-30
    • 2014-12-16
    • 2014-04-30
    • 1970-01-01
    • 2018-01-15
    • 1970-01-01
    • 1970-01-01
    • 2014-06-15
    • 2020-04-12
    相关资源
    最近更新 更多