/*
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 com.googlecode.totallylazy.annotations.tailrec;
import static java.lang.Long.MAX_VALUE;
import static java.lang.Long.MIN_VALUE;
import static java.math.BigInteger.valueOf;
public final class LongOperators implements Operators<Long>, IntegralOperators {
public static LongOperators Instance = new LongOperators();
private LongOperators() {
}
public final Class<Long> forClass() {
return Long.class;
}
public final int priority() {
return 2;
}
public final Number increment(Long value) {
if (value < MAX_VALUE)
return value + 1;
return BigIntegerOperators.Instance.increment(valueOf(value));
}
public final Number decrement(Long value) {
if (value > MIN_VALUE)
return value - 1;
return BigIntegerOperators.Instance.decrement(valueOf(value));
}
@Override
public Number absolute(Long value) {
return Math.abs(value);
}
public final Number negate(Long value) {
if (value > MIN_VALUE)
return -value;
return valueOf(value).negate();
}
public final boolean isZero(Long value) {
return value == 0;
}
public final boolean isPositive(Long value) {
return value > 0;
}
public final boolean isNegative(Long value) {
return value < 0;
}
public final boolean equalTo(Number x, Number y) {
return x.longValue() == y.longValue();
}
public final boolean lessThan(Number x, Number y) {
return x.longValue() < y.longValue();
}
public final Number add(Number x, Number y) {
long lx = x.longValue(), ly = y.longValue();
long ret = lx + ly;
if ((ret ^ lx) < 0 && (ret ^ ly) < 0)
return BigIntegerOperators.Instance.add(x, y);
return ret;
}
public final Number multiply(Number x, Number y) {
long lx = x.longValue(), ly = y.longValue();
long ret = lx * ly;
if (ly != 0 && ret / ly != lx)
return BigIntegerOperators.Instance.multiply(x, y);
return ret;
}
@tailrec
public static long gcd(long x, long y) {
if (y == 0) return x;
return gcd(y, x % y);
}
public final Number divide(Number x, Number y) {
long n = x.longValue();
long val = y.longValue();
long gcd = gcd(n, val);
if (gcd == 0)
return 0;
n = n / gcd;
long d = val / gcd;
if (d == 1)
return reduce(n);
if (d < 0) {
n = -n;
d = -d;
}
return new Ratio(valueOf(n), valueOf(d));
}
public final Number quotient(Number x, Number y) {
return quotient(x.longValue(), y.longValue());
}
public static long quotient(long x, long y) {
return x / y;
}
public final Number remainder(Number x, Number y) {
return x.longValue() % y.longValue();
}
@Override
public Number gcd(Number x, Number y) {
return gcd(x.longValue(), y.longValue());
}
@Override
public Number lcm(Number x, Number y) {
return lcm(x.longValue(), y.longValue());
}
public static long lcm(long x, long y){
if(x == 0 || y == 0) return 0;
return Math.abs(y * quotient(x, gcd(x, y)));
}
public static Number reduce(long value) {
if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE)
return (int) value;
else
return value;
}
}