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
是javalong
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);
}