blob: 58f859d53526a9f75d84c7917cde84213759b636 [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;
/** Modular arithmetics */
public class Modular {
static final long MAX_SQRT_LONG = (long)Math.sqrt(Long.MAX_VALUE);
/** Compute 2^e mod n */
public static long mod(long e, long n) {
final int HALF = (63 - Long.numberOfLeadingZeros(n)) >> 1;
final int FULL = HALF << 1;
final long ONES = (1 << HALF) - 1;
long r = 2;
for (long mask = Long.highestOneBit(e) >> 1; mask > 0; mask >>= 1) {
if (r <= MAX_SQRT_LONG) {
r *= r;
if (r >= n) r %= n;
} else {
// r^2 will overflow
final long high = r >>> HALF;
final long low = r &= ONES;
r *= r;
if (r >= n) r %= n;
if (high != 0) {
long s = high * high;
if (s >= n) s %= n;
for(int i = 0; i < FULL; i++)
if ((s <<= 1) >= n) s -= n;
if (low == 0)
r = s;
else {
long t = high * low;
if (t >= n) t %= n;
for(int i = -1; i < HALF; i++)
if ((t <<= 1) >= n) t -= n;
r += s;
if (r >= n) r -= n;
r += t;
if (r >= n) r -= n;
}
}
}
if ((e & mask) != 0) {
r <<= 1;
if (r >= n) r -= n;
}
}
return r;
}
/** Given x in [0,1) and a in (-1,1),
* return (x, a) mod 1.0.
*/
public static double addMod(double x, final double a) {
x += a;
return x >= 1? x - 1: x < 0? x + 1: x;
}
/** Given 0 < x < y,
* return x^(-1) mod y.
*/
public static long modInverse(final long x, final long y) {
if (x == 1) return 1;
long a = 1;
long b = 0;
long c = x;
long u = 0;
long v = 1;
long w = y;
for(;;) {
{
final long q = w/c;
w -= q*c;
u -= q*a;
if (w == 1) return u > 0? u: u + y;
v -= q*b;
}
{
final long q = c/w;
c -= q*w;
a -= q*u;
if (c == 1) return a > 0? a: a + y;
b -= q*v;
}
}
}
}