import java.math.BigInteger;
import edu.mit.ai.psg.traveler.*;
import java.lang.reflect.*;
@author
public class FutureFactorialNoInner {
static final BigInteger ONE = BigInteger.ONE;
static final BigInteger TWO = new BigInteger("2");
public static void main(String[] args) {
BigInteger arg = new BigInteger(args.length == 0 ? "8" : args[0]);
System.out.println(factorial(arg));
}
@throwsIllegalArgumentException
public static BigInteger factorial(final BigInteger n) {
if (1 == n.signum()) return rangeProduct(ONE, n);
else
throw new IllegalArgumentException("n < 1");
}
public static BigInteger rangeProduct(final BigInteger lo,
final BigInteger hi) {
if (lo.equals(hi)) return lo;
else if ((lo.add(BigInteger.ONE)).equals(hi))
return lo.multiply(hi);
else {
final BigInteger mid = (lo.add(hi)).divide(TWO);
Future loProd = new RangeProductFuture(lo, mid);
Future hiProd = new RangeProductFuture(mid.add(ONE), hi);
return ((BigInteger)loProd.value()).multiply((BigInteger)hiProd.value());
}
}
}
final class RangeProductFuture extends Future {
BigInteger lo, hi;
RangeProductFuture(BigInteger lo, BigInteger hi) {
this.lo = lo; this.hi = hi; start(); }
public Object compute() { return FutureFactorialNoInner.rangeProduct(lo, hi); }
}
abstract class Future implements Runnable, Cloneable {
private State myState = UNINITIALIZED;
private Object myValue = null;
private static final
State UNINITIALIZED = new State("Uninitialized");
private static final
State INITIALIZED_AND_STARTED= new State("Initialized and started");
private static final
State COMPLETED_RETURN = new State("Completed with return");
private static final
State COMPLETED_THROW = new State("Completed with throw");
Future() {}
@throwsIllegalStateException
public synchronized void start() {
if (myState == UNINITIALIZED) {
Thread thread = new Thread(this);
thread.start();
myState = INITIALIZED_AND_STARTED;
return;
} else {
throw new IllegalStateException("Already started.");
}
}
protected abstract Object compute();
public synchronized void run() {
while (myState == UNINITIALIZED)
try { this.wait(); } catch (InterruptedException e) {}
if (myState == INITIALIZED_AND_STARTED) {
try {
myValue = compute();
myState = COMPLETED_RETURN;
} catch(Throwable t) {
myValue = t;
myState = COMPLETED_THROW;
}
this.notifyAll();
}
}
@throwsError{@link #compute()}@throwsRuntimeException{@link #compute()}
public synchronized Object value() {
while (! (myState == COMPLETED_RETURN || myState == COMPLETED_THROW)) {
try {
this.wait();
}
catch (InterruptedException e) {
throw new Error(e.toString());
}
}
if (myState == COMPLETED_RETURN)
return myValue;
else { Throwable thrown = (Throwable) myValue;
if (dbgLev> 0) thrown.printStackTrace();
if (thrown instanceof Error) throw (Error) thrown;
else throw (RuntimeException) thrown;
}
}
public String toString() {
return "Future(state="+myState+", value="+myValue+")";}
public static int dbgLev = 1;
}
class State {
private String stateName;
State(String stateName) { this.stateName = stateName; }
public String toString() { return stateName; }
}