blob: d58e0c3586932237ea09095ecdf1502d886fbe71 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.examples.pi.math;
/** Montgomery method.
*
* References:
*
* [1] Richard Crandall and Carl Pomerance. Prime Numbers: A Computational
* Perspective. Springer-Verlag, 2001.
*
* [2] Peter Montgomery. Modular multiplication without trial division.
* Math. Comp., 44:519-521, 1985.
*/
class Montgomery {
protected final Product product = new Product();
protected long N;
protected long N_I; // N'
protected long R;
protected long R_1; // R - 1
protected int s;
/** Set the modular and initialize this object. */
Montgomery set(long n) {
if (n % 2 != 1)
throw new IllegalArgumentException("n % 2 != 1, n=" + n);
N = n;
R = Long.highestOneBit(n) << 1;
N_I = R - Modular.modInverse(N, R);
R_1 = R - 1;
s = Long.numberOfTrailingZeros(R);
return this;
}
/** Compute 2^y mod N for N odd. */
long mod(final long y) {
long p = R - N;
long x = p << 1;
if (x >= N) x -= N;
for(long mask = Long.highestOneBit(y); mask > 0; mask >>>= 1) {
p = product.m(p, p);
if ((mask & y) != 0) p = product.m(p, x);
}
return product.m(p, 1);
}
class Product {
private final LongLong x = new LongLong();
private final LongLong xN_I = new LongLong();
private final LongLong aN = new LongLong();
long m(final long c, final long d) {
LongLong.multiplication(x, c, d);
// a = (x * N')&(R - 1) = ((x & R_1) * N') & R_1
final long a = LongLong.multiplication(xN_I, x.and(R_1), N_I).and(R_1);
LongLong.multiplication(aN, a, N);
final long z = aN.plusEqual(x).shiftRight(s);
return z < N? z: z - N;
}
}
}