/* This code is a a heavily modified version of Numbers from Rich Hickeys clojure core, see Numbers.java for copyright */ package com.googlecode.totallylazy.numbers; import java.math.BigInteger; import static java.math.BigInteger.ONE; import static java.math.BigInteger.ZERO; import static java.math.BigInteger.valueOf; public final class BigIntegerOperators implements Operators<BigInteger>, IntegralOperators { public static BigIntegerOperators Instance = new BigIntegerOperators(); private BigIntegerOperators() {} public final Class<BigInteger> forClass() { return BigInteger.class; } public final int priority() { return 3; } public final Number increment(BigInteger value) { return reduce(value.add(ONE)); } public final Number decrement(BigInteger value) { return reduce(value.subtract(ONE)); } public final boolean isZero(BigInteger value) { return value.signum() == 0; } public final boolean isPositive(BigInteger value) { return value.signum() == 1; } public final boolean isNegative(BigInteger value) { return value.signum() == -1; } public final boolean equalTo(Number x, Number y) { return bigInteger(x).equals(bigInteger(y)); } public final boolean lessThan(Number x, Number y) { return bigInteger(x).compareTo(bigInteger(y)) < 0; } @Override public Number absolute(BigInteger value) { return value.abs(); } public final Number negate(BigInteger value) { return value.negate(); } public final Number add(Number x, Number y) { return reduce(bigInteger(x).add(bigInteger(y))); } public final Number multiply(Number x, Number y) { return reduce(bigInteger(x).multiply(bigInteger(y))); } public final Number divide(Number x, Number y) { return divide(bigInteger(x), bigInteger(y)); } public static Number divide(BigInteger n, BigInteger d) { if (d.equals(ZERO)) { throw new ArithmeticException("Divide by zero"); } BigInteger gcd = n.gcd(d); if (gcd.equals(ZERO)) { return 0; } n = n.divide(gcd); d = d.divide(gcd); if (d.equals(BigInteger.ONE)) { return reduce(n); } if (d.equals(BigInteger.ONE.negate())) { return reduce(n.negate()); } return new Ratio((d.signum() < 0 ? n.negate() : n), (d.signum() < 0 ? d.negate() : d)); } public static Number reduce(BigInteger value) { int bitLength = value.bitLength(); if (bitLength < 32) return value.intValue(); else if (bitLength < 64) return value.longValue(); else return value; } public final Number quotient(Number x, Number y) { BigInteger bigInteger = bigInteger(x); BigInteger val = bigInteger(y); return quotient(bigInteger, val); } public static BigInteger quotient(BigInteger x, BigInteger y) { return x.divide(y); } public final Number remainder(Number x, Number y) { return bigInteger(x).remainder(bigInteger(y)); } @Override public Number gcd(Number x, Number y) { return gcd(bigInteger(x), bigInteger(y)); } public static BigInteger gcd(BigInteger bigInteger, BigInteger val) { return bigInteger.gcd(val); } @Override public Number lcm(Number x, Number y) { return lcm(bigInteger(x), bigInteger(y)); } public static BigInteger lcm(BigInteger x, BigInteger y) { if(x.signum() == 0 || y.signum() == 0) return ZERO; return y.multiply(quotient(x, gcd(x, y))).abs(); } public static BigInteger bigInteger(Number value) { if (value instanceof BigInteger) { return (BigInteger) value; } return valueOf(value.longValue()); } }