/*
This code is a a heavily modified version of Numbers from Rich Hickeys clojure core
*/
/**
* Copyright (c) Rich Hickey. All rights reserved.
* The use and distribution terms for this software are covered by the
* Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
* which can be found in the file epl-v10.html at the root of this distribution.
* By using this software in any fashion, you are agreeing to be bound by
* the terms of this license.
* You must not remove this notice, or any other, from this software.
**/
/* rich Mar 31, 2008 */
package com.googlecode.totallylazy.numbers;
import com.googlecode.totallylazy.functions.CurriedBinary;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.functions.CurriedMonoid;
import com.googlecode.totallylazy.Computation;
import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.Pair;
import com.googlecode.totallylazy.predicates.Predicate;
import com.googlecode.totallylazy.predicates.Predicates;
import com.googlecode.totallylazy.Segment;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.Sequences;
import com.googlecode.totallylazy.functions.Unary;
import com.googlecode.totallylazy.Unchecked;
import com.googlecode.totallylazy.predicates.LogicalPredicate;
import com.googlecode.totallylazy.predicates.RemainderIs;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.Iterator;
import static com.googlecode.totallylazy.functions.Callables.first;
import static com.googlecode.totallylazy.Computation.computation;
import static com.googlecode.totallylazy.Option.none;
import static com.googlecode.totallylazy.Option.some;
import static com.googlecode.totallylazy.Pair.reduceLeftShift;
import static com.googlecode.totallylazy.predicates.Predicates.is;
import static com.googlecode.totallylazy.Segment.constructors.segment;
import static com.googlecode.totallylazy.Segment.constructors.unique;
import static com.googlecode.totallylazy.Sequences.characters;
import static com.googlecode.totallylazy.Sequences.iterate;
import static com.googlecode.totallylazy.Sequences.repeat;
import static com.googlecode.totallylazy.predicates.WherePredicate.where;
public class Numbers {
public static final Number POSITIVE_INFINITY = Double.POSITIVE_INFINITY;
public static final Number NEGATIVE_INFINITY = Double.NEGATIVE_INFINITY;
public static final ArithmeticException DIVIDE_BY_ZERO = new ArithmeticException("Divide by zero");
public static Function1<Number, Integer> intValue = Number::intValue;
public static Sequence<Number> range(final Number start) {
return iterate(increment, start);
}
public static Sequence<Number> range(final Number start, final Number end) {
if (lessThan(end, start)) return range(start, end, 1);
return range(start).takeWhile(lessThanOrEqualTo(end));
}
public static Sequence<Number> range(final Number start, final Number end, final Number step) {
Number absoluteStep = Numbers.absolute(step);
if (lessThan(end, start)) return iterate(subtract(absoluteStep), start).takeWhile(greaterThanOrEqualTo(end));
return iterate(add(absoluteStep), start).takeWhile(lessThanOrEqualTo(end));
}
public static Number absolute(Number number) {
return operatorsFor(number.getClass()).absolute(number);
}
public static Option<Number> valueOf(String string) {
try {
return some(reduce(new BigDecimal(string)));
} catch (Exception e) {
return none(Number.class);
}
}
public static Function1<Object, Number> valueOf = value -> Numbers.valueOf(value.toString()).get();
public static Sequence<Number> numbers(Number... numbers) {
return Sequences.sequence(numbers);
}
public static Sequence<Number> numbers(final int[] numbers) {
return new Sequence<Number>() {
public Iterator<Number> iterator() {
return new IntIterator(numbers);
}
};
}
public static Sequence<Number> primeFactors(final Number number) {
return Segment.methods.sequence(factor(primes, number));
}
static Segment<Number> factor(Segment<Number> primes, Number number) {
Number prime = primes.head();
if (greaterThan(squared(prime), number)) return segment(number);
if (isZero(remainder(number, prime))) return unique(prime, factor(primes, quotient(number, prime)));
return factor(primes.tail(), number);
}
public static Number squareRoot(Number number) {
return Math.sqrt(number.doubleValue());
}
public static Unary<Number> squareRoot = Numbers::squareRoot;
public static Unary<Number> squared = Numbers::squared;
public static Unary<Number> squared() {
return squared;
}
public static Number squared(Number value) {
return multiply(value, value);
}
public static LogicalPredicate<Number> not(Number value) {
return Predicates.not(value);
}
public static LogicalPredicate<Number> not(Predicate<? super Number> predicate) {
return Predicates.not(predicate);
}
public static LogicalPredicate<Number> even = remainderIs(2, 0);
public static LogicalPredicate<Number> even() {
return even;
}
public static LogicalPredicate<Number> odd = remainderIs(2, 1);
public static LogicalPredicate<Number> odd() {
return odd;
}
public static LogicalPredicate<Number> prime = new LogicalPredicate<Number>() {
public final boolean matches(final Number candidate) {
return isPrime(candidate);
}
};
public static LogicalPredicate<Number> prime() {
return prime;
}
public static LogicalPredicate<Number> isPrime() {
return prime;
}
public static boolean isPrime(Number candidate) {
return primes().takeWhile(where(squared, lessThanOrEqualTo(candidate))).forAll(where(remainder(candidate), is(not(zero))));
}
public static LogicalPredicate<Number> remainderIs(final Number divisor, final Number remainder) {
return new RemainderIs(divisor, remainder);
}
public static Sequence<Number> probablePrimes() {
return iterate(nextProbablePrime(), BigInteger.valueOf(2)).map(reduce());
}
private static Unary<BigInteger> nextProbablePrime() {
return BigInteger::nextProbablePrime;
}
public static Unary<Number> nextPrime = Numbers::nextPrime;
public static Unary<Number> nextPrime() {
return nextPrime;
}
public static Computation<Number> primes = Computation.cons(2, computation(3, nextPrime));
public static Sequence<Number> primes() {
return primes;
}
public static Number nextPrime(Number number) {
return iterate(add(2), number).filter(prime).second();
}
public static Sequence<Number> fibonacci() {
return computation(Pair.<Number, Number>pair(0, 1), reduceLeftShift(sum)).map(first(Number.class));
}
public static Sequence<Number> powersOf(Number amount) {
return Computation.iterate(multiply(amount), 1);
}
public static Operators<Number> operatorsFor(Class<? extends Number> numberClass) {
return Unchecked.cast(internalOperatorsFor(numberClass));
}
private static Operators<? extends Number> internalOperatorsFor(Class<? extends Number> numberClass) {
if (numberClass == Short.class) return ShortOperators.Instance;
if (numberClass == Integer.class) return IntegerOperators.Instance;
if (numberClass == Long.class) return LongOperators.Instance;
if (numberClass == BigInteger.class) return BigIntegerOperators.Instance;
if (numberClass == BigDecimal.class) return BigDecimalOperators.Instance;
if (numberClass == Ratio.class) return RatioOperators.Instance;
if (numberClass == Float.class) return FloatOperators.Instance;
if (numberClass == Double.class) return DoubleOperators.Instance;
throw new UnsupportedOperationException("Unsupported number " + numberClass);
}
public static Operators<Number> operatorsFor(Number number) {
if(number instanceof Num) return new NumOperator(operatorsFor(((Num) number).value()));
return operatorsFor(number.getClass());
}
public static Operators<Number> operatorsFor(Number a, Number b) {
Operators<Number> aOperators = operatorsFor(a);
Operators<Number> bOperators = operatorsFor(b);
return aOperators.priority() > bOperators.priority() ? aOperators : bOperators;
}
public static Number negate(Number value) {
return operatorsFor(value).negate(value);
}
public static Unary<Number> increment = Numbers::increment;
public static Unary<Number> increment() {
return increment;
}
public static Number increment(Number value) {
return operatorsFor(value).increment(value);
}
public static Unary<Number> decrement = Numbers::decrement;
public static Unary<Number> decrement() {
return decrement;
}
public static Number decrement(Number value) {
return operatorsFor(value).decrement(value);
}
public static LogicalPredicate<Number> zero = new LogicalPredicate<Number>() {
@Override
public boolean matches(Number other) {
return isZero(other);
}
};
public static LogicalPredicate<Number> zero() {
return zero;
}
public static LogicalPredicate<Number> isZero = zero;
public static LogicalPredicate<Number> isZero() {
return zero;
}
public static boolean isZero(Number value) {
return operatorsFor(value).isZero(value);
}
public static boolean isPositive(Number value) {
return operatorsFor(value).isPositive(value);
}
public static boolean isNegative(Number value) {
return operatorsFor(value).isNegative(value);
}
public static boolean equalTo(Number x, Number y) {
return operatorsFor(x, y).equalTo(x, y);
}
public static LogicalPredicate<Number> lessThan(final Number value) {
return new LessThanPredicate(value);
}
public static boolean lessThan(Number x, Number y) {
return operatorsFor(x, y).lessThan(x, y);
}
public static LogicalPredicate<Number> lessThanOrEqualTo(final Number value) {
return new LessThanOrEqualToPredicate(value);
}
public static boolean lessThanOrEqualTo(Number x, Number y) {
return !operatorsFor(x, y).lessThan(y, x);
}
public static LogicalPredicate<Number> greaterThan(final Number value) {
return new GreaterThanPredicate(value);
}
public static boolean greaterThan(Number x, Number y) {
return operatorsFor(x, y).lessThan(y, x);
}
public static LogicalPredicate<Number> greaterThanOrEqualTo(final Number value) {
return new GreaterThanOrEqualToPredicate(value);
}
public static boolean greaterThanOrEqualTo(Number x, Number y) {
return !operatorsFor(x, y).lessThan(x, y);
}
public static LogicalPredicate<Number> between(final Number a, final Number b) {
return new BetweenPredicate(a, b);
}
public static int compare(Number x, Number y) {
Operators<Number> operators = operatorsFor(x, y);
if (operators.lessThan(x, y)) return -1;
if (operators.lessThan(y, x)) return 1;
return 0;
}
public static Comparator<Number> ascending() {
return Numbers::compare;
}
public static Comparator<Number> descending() {
return (x, y) -> compare(y, x);
}
public static Function1<Iterable<Number>, Number> sumIterable() {
return numbers -> Sequences.reduceLeft(numbers, sum());
}
public static final CurriedMonoid<Number> average = new Average();
public static CurriedMonoid<Number> average() {
return average;
}
public static final CurriedMonoid<Number> sum = new Sum();
public static final CurriedMonoid<Number> Σ = sum;
public static CurriedMonoid<Number> sum() {
return sum;
}
public static final CurriedMonoid<Number> add = sum;
public static CurriedMonoid<Number> add() {
return add;
}
public static Unary<Number> add(final Number amount) {
return add.apply(amount);
}
public static Number add(Number x, Number y) {
return operatorsFor(x, y).add(x, y);
}
public static CurriedBinary<Number> subtract = Numbers::subtract;
public static CurriedBinary<Number> subtract() {
return subtract;
}
public static Unary<Number> subtract(final Number amount) {
return subtract.flip().apply(amount);
}
public static Number subtract(Number x, Number y) {
return operatorsFor(x, y).add(x, operatorsFor(y).negate(y));
}
public static CurriedMonoid<Number> product = new Product();
public static CurriedMonoid<Number> product() {
return product;
}
public static CurriedMonoid<Number> multiply = product;
public static CurriedMonoid<Number> multiply() {
return multiply;
}
public static Unary<Number> multiply(final Number multiplicand) {
return multiply.apply(multiplicand);
}
public static Number multiply(Number x, Number y) {
return operatorsFor(x, y).multiply(x, y);
}
public static Number divide(Number x, Number y) {
throwIfZero(y);
return operatorsFor(x, y).divide(x, y);
}
public static Unary<Number> divide(final Number divisor) {
return divide.flip().apply(divisor);
}
public static CurriedBinary<Number> divide = Numbers::divide;
public static CurriedBinary<Number> divide() {
return divide;
}
public static Number quotient(Number x, Number y) {
throwIfZero(y);
return reduce(operatorsFor(x, y).quotient(x, y));
}
public static Unary<Number> mod(final Number divisor) {
return mod().apply(divisor);
}
public static CurriedBinary<Number> remainder = Numbers::remainder;
public static CurriedBinary<Number> remainder() {
return remainder;
}
public static CurriedBinary<Number> mod = remainder.flip();
public static CurriedBinary<Number> mod() {
return mod;
}
public static Unary<Number> remainder(final Number dividend) {
return remainder().apply(dividend);
}
public static Number remainder(Number dividend, Number divisor) {
throwIfZero(divisor);
return reduce(operatorsFor(dividend, divisor).remainder(dividend, divisor));
}
private static void throwIfZero(Number value) {
if (operatorsFor(value).isZero(value)) {
throw DIVIDE_BY_ZERO;
}
}
public static Number number(Number value) {
return reduce(value);
}
public static Number reduce(Number value) {
if (value instanceof Long)
return LongOperators.reduce(value.longValue());
else if (value instanceof BigInteger)
return BigIntegerOperators.reduce((BigInteger) value);
return value;
}
public static Unary<Number> reduce() {
return Numbers::reduce;
}
public static Function1<Number, Character> toCharacter() {
return number -> (char) number.shortValue();
}
public static String toLexicalString(Number value, final Number minValue, final Number maxValue) {
String offset = add(value, negate(minValue)).toString();
int maxSize = add(maxValue, negate(minValue)).toString().length();
return repeat('0').take(maxSize - offset.length()).join(characters(offset)).toString("");
}
public static Number parseLexicalString(String value, final Number minValue) {
return add(valueOf(value).get(), minValue);
}
public static Maximum maximum = new Maximum();
public static Maximum maximum() {
return maximum;
}
public static Minimum minimum = new Minimum();
public static Minimum minimum() {
return minimum;
}
public static Lcm lcm = new Lcm();
public static Lcm lcm() {
return lcm;
}
public static Number lcm(Number x, Number y) {
return integralOperatorsFor(x, y).lcm(x, y);
}
private static IntegralOperators integralOperatorsFor(Number x, Number y) {
Operators<?> numberOperators = operatorsFor(x, y);
if (numberOperators instanceof IntegralOperators) return (IntegralOperators) numberOperators;
throw new UnsupportedOperationException();
}
public static Gcd gcd = new Gcd();
public static Gcd gcd() {
return gcd;
}
public static Number gcd(Number x, Number y) {
return integralOperatorsFor(x, y).gcd(x, y);
}
}