Java 大数的模约化

Java 大数的模约化,java,long-integer,arithmetic-expressions,Java,Long Integer,Arithmetic Expressions,对于一个玩具程序,我需要一种有效的计算方法 (2**64 * x) % m 其中,x和m是javalongs,**表示幂运算。这可以计算为 BigInteger.valueOf(x).shiftLeft(64).mod(BigInteger.valueOf(m)).longValue() 或者反复向左移动x并减小,但两者都非常缓慢。这不是过早的优化 澄清 ——任何使用biginger的算法都可能比上面的表达式慢 ——您可以假设m对于int来说太大,否则 long n = (1L<&

对于一个玩具程序,我需要一种有效的计算方法

(2**64 * x) % m
其中,
x
m
是java
long
s,
**
表示幂运算。这可以计算为

 BigInteger.valueOf(x).shiftLeft(64).mod(BigInteger.valueOf(m)).longValue()
或者反复向左移动
x
并减小,但两者都非常缓慢。这不是过早的优化

澄清 ——任何使用
biginger
的算法都可能比上面的表达式慢

——您可以假设
m
对于
int
来说太大,否则

 long n = (1L<<32) % m; 
 return ((n*n) % m) * (x % m)) % m
long n=(1L一般形式:
(a1*a2*a3…*an)%m=[(a1%m)*(a2%m)*…*(a3%m)]%m

应用上述公式,我们有:

(2^64*x)%m=((2^64)%m)*(x%m))%m

对于第一部分:
2^64 mod m
。我可以做一个更一般的情况:
2^t mod m
。我有这个伪代码。In将在
N(log t)
次中运行。这个只用于t和m的伪代码是普通整数。根据t和m的范围,您可以在适当的点修正内部函数计算以使用biginger

long solve(long t, long m) {
   if (t == 0) return 1 % m;
   if (t == 1) return t % m;
   long res = solve(t/2, m);
   res = (res * res) % m;
   if (t % 2 == 1) res = (res * 2) % m;
   return res;
}
感谢OldCurmudgeon。上面的代码可以是一行简单的代码:

BigInteger res = (new BigInteger("2")).
   modPow(new BigInteger("64"), new BigInteger("" + m));
这是
modPow
的实现。这个实现使用了不同的方法。算法从m开始:将m分解为
m=2^k*q
。然后将找到2^k和q的模,然后使用
中国提醒定理
组合结果

 public BigInteger modPow(BigInteger exponent, BigInteger m) {
        if (m.signum <= 0)
            throw new ArithmeticException("BigInteger: modulus not positive");

        // Trivial cases
        if (exponent.signum == 0)
            return (m.equals(ONE) ? ZERO : ONE);

        if (this.equals(ONE))
            return (m.equals(ONE) ? ZERO : ONE);

        if (this.equals(ZERO) && exponent.signum >= 0)
            return ZERO;

        if (this.equals(negConst[1]) && (!exponent.testBit(0)))
            return (m.equals(ONE) ? ZERO : ONE);

        boolean invertResult;
        if ((invertResult = (exponent.signum < 0)))
            exponent = exponent.negate();

        BigInteger base = (this.signum < 0 || this.compareTo(m) >= 0
                           ? this.mod(m) : this);
        BigInteger result;
        if (m.testBit(0)) { // odd modulus
            result = base.oddModPow(exponent, m);
        } else {
            /*
             * Even modulus.  Tear it into an "odd part" (m1) and power of two
             * (m2), exponentiate mod m1, manually exponentiate mod m2, and
             * use Chinese Remainder Theorem to combine results.
             */

            // Tear m apart into odd part (m1) and power of 2 (m2)
            int p = m.getLowestSetBit();   // Max pow of 2 that divides m

            BigInteger m1 = m.shiftRight(p);  // m/2**p
            BigInteger m2 = ONE.shiftLeft(p); // 2**p

            // Calculate new base from m1
            BigInteger base2 = (this.signum < 0 || this.compareTo(m1) >= 0
                                ? this.mod(m1) : this);

            // Caculate (base ** exponent) mod m1.
            BigInteger a1 = (m1.equals(ONE) ? ZERO :
                             base2.oddModPow(exponent, m1));

            // Calculate (this ** exponent) mod m2
            BigInteger a2 = base.modPow2(exponent, p);

            // Combine results using Chinese Remainder Theorem
            BigInteger y1 = m2.modInverse(m1);
            BigInteger y2 = m1.modInverse(m2);

            if (m.mag.length < MAX_MAG_LENGTH / 2) {
                result = a1.multiply(m2).multiply(y1).add(a2.multiply(m1).multiply(y2)).mod(m);
            } else {
                MutableBigInteger t1 = new MutableBigInteger();
                new MutableBigInteger(a1.multiply(m2)).multiply(new MutableBigInteger(y1), t1);
                MutableBigInteger t2 = new MutableBigInteger();
                new MutableBigInteger(a2.multiply(m1)).multiply(new MutableBigInteger(y2), t2);
                t1.add(t2);
                MutableBigInteger q = new MutableBigInteger();
                result = t1.divide(new MutableBigInteger(m), q).toBigInteger();
            }
        }

        return (invertResult ? result.modInverse(m) : result);
    }
public biginger modPow(biginger指数,biginger m){
如果(m.signum=0)
返回零;
if(this.equals(negConst[1])&(!exponent.testBit(0)))
回报率(m等于(一)-零:一);
布尔结果;
如果((invertResult=(exponent.signum<0)))
指数=指数。否定();
biginger base=(this.signum<0 | | this.compareTo(m)>=0
?本模块(m):本模块;
大整数结果;
if(m.testBit(0)){//奇数模
结果=基准oddModPow(指数,m);
}否则{
/*
*偶数模。把它分成一个“奇数部分”(m1)和二的幂
*(m2),对m1模求幂,手动对m2模求幂,以及
*使用中国剩余定理合并结果。
*/
//将m分成奇数部分(m1)和2的幂(m2)
int p=m.getLowestSetBit();//除以m的2的最大功率
大整数m1=m.shiftRight(p);//m/2**p
BigInteger m2=1.shiftLeft(p);//2**p
//根据m1计算新基数
BigInteger base2=(this.signum<0 | | this.compareTo(m1)>=0
?本模块(m1):本模块;
//计算(基准**指数)模型m1。
大整数a1=(m1.等于(一)?零:
base2.oddModPow(指数,m1));
//计算(该**指数)mod m2
BigInteger a2=base.modPow2(指数,p);
//使用中国剩余定理合并结果
大整数y1=m2.modInverse(m1);
大整数y2=m1.模逆(m2);
如果(m.mag.length<最大mag\u length/2){
结果=a1.乘(m2).乘(y1).加(a2.乘(m1).乘(y2)).模(m);
}否则{
MutableBigInteger t1=新的MutableBigInteger();
新的MutableBigInteger(a1.乘法(m2))。乘法(新的MutableBigInteger(y1),t1);
MutableBigInteger t2=新的MutableBigInteger();
新的mutablebiginger(a2.乘法(m1)).乘法(新的mutablebiginger(y2),t2);
t1.添加(t2);
MutableBigInteger q=新的MutableBigInteger();
结果=t1.divide(新的可变biginger(m),q).tobiginger();
}
}
返回(反转结果?结果。修改反转(m):结果);
}

对于第二部分:您可以很容易地使用
biginger
或简单的正常计算,这取决于x和m的范围。

您的意思是:(2^64*x)%m?关于
m
和/或
x
的任何限制/信息?@hqt是的,假设您不是指
xor
。我的意思是\$x^{64}\$但是tex符号不太适用。@Sirko没有,只是它们很大。在-
int
案例中的拟合很容易,而且可以单独处理。
BigInteger
可以处理
2^64%m
@OldCurmudgeon我编辑了我的答案。似乎modPow实现更快,因为java实现包括了我的算法rithm(break exponent/2)和一些修改…@hqt恐怕你错过了我的
biginger
方法(比我需要的慢)。
 public BigInteger modPow(BigInteger exponent, BigInteger m) {
        if (m.signum <= 0)
            throw new ArithmeticException("BigInteger: modulus not positive");

        // Trivial cases
        if (exponent.signum == 0)
            return (m.equals(ONE) ? ZERO : ONE);

        if (this.equals(ONE))
            return (m.equals(ONE) ? ZERO : ONE);

        if (this.equals(ZERO) && exponent.signum >= 0)
            return ZERO;

        if (this.equals(negConst[1]) && (!exponent.testBit(0)))
            return (m.equals(ONE) ? ZERO : ONE);

        boolean invertResult;
        if ((invertResult = (exponent.signum < 0)))
            exponent = exponent.negate();

        BigInteger base = (this.signum < 0 || this.compareTo(m) >= 0
                           ? this.mod(m) : this);
        BigInteger result;
        if (m.testBit(0)) { // odd modulus
            result = base.oddModPow(exponent, m);
        } else {
            /*
             * Even modulus.  Tear it into an "odd part" (m1) and power of two
             * (m2), exponentiate mod m1, manually exponentiate mod m2, and
             * use Chinese Remainder Theorem to combine results.
             */

            // Tear m apart into odd part (m1) and power of 2 (m2)
            int p = m.getLowestSetBit();   // Max pow of 2 that divides m

            BigInteger m1 = m.shiftRight(p);  // m/2**p
            BigInteger m2 = ONE.shiftLeft(p); // 2**p

            // Calculate new base from m1
            BigInteger base2 = (this.signum < 0 || this.compareTo(m1) >= 0
                                ? this.mod(m1) : this);

            // Caculate (base ** exponent) mod m1.
            BigInteger a1 = (m1.equals(ONE) ? ZERO :
                             base2.oddModPow(exponent, m1));

            // Calculate (this ** exponent) mod m2
            BigInteger a2 = base.modPow2(exponent, p);

            // Combine results using Chinese Remainder Theorem
            BigInteger y1 = m2.modInverse(m1);
            BigInteger y2 = m1.modInverse(m2);

            if (m.mag.length < MAX_MAG_LENGTH / 2) {
                result = a1.multiply(m2).multiply(y1).add(a2.multiply(m1).multiply(y2)).mod(m);
            } else {
                MutableBigInteger t1 = new MutableBigInteger();
                new MutableBigInteger(a1.multiply(m2)).multiply(new MutableBigInteger(y1), t1);
                MutableBigInteger t2 = new MutableBigInteger();
                new MutableBigInteger(a2.multiply(m1)).multiply(new MutableBigInteger(y2), t2);
                t1.add(t2);
                MutableBigInteger q = new MutableBigInteger();
                result = t1.divide(new MutableBigInteger(m), q).toBigInteger();
            }
        }

        return (invertResult ? result.modInverse(m) : result);
    }