<commit_before>/*
This code is a a heavily modified version of Numbers from Rich Hickeys clojure core
 */

/**
 *   Copyright (c) <NAME>. 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.Callable1;
import com.googlecode.totallylazy.Callable2;
import com.googlecode.totallylazy.Computation;
import com.googlecode.totallylazy.Function1;
import com.googlecode.totallylazy.Function2;
import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.Pair;
import com.googlecode.totallylazy.Predicate;
import com.googlecode.totallylazy.Predicates;
import com.googlecode.totallylazy.Segment;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.Sequences;
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.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.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 ArithmeticException DIVIDE_BY_ZERO = new ArithmeticException("Divide by zero");
    public static Function1<Number, Integer> intValue = new Function1<Number, Integer>() {
        @Override
        public Integer call(Number number) throws Exception {
            return 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) {
        if (lessThan(end, start)) return iterate(add(step), start).takeWhile(greaterThanOrEqualTo(end));
        return iterate(add(step), start).takeWhile(lessThanOrEqualTo(end));
    }

    public static Option<Number> valueOf(String string) {
        try {
            return some(reduce(new BigDecimal(string)));
        } catch (Exception e) {
            return none(Number.class);
        }
    }

    public static Callable1<Object, Number> valueOf = new Callable1<Object, Number>() {
        @Override
        public Number call(Object value) throws Exception {
            return 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 Function1<Number, Number> squared = new Function1<Number, Number>() {
        @Override
        public Number call(Number number) throws Exception {
            return squared(number);
        }
    };

    public static Function1<Number, 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 Function1<BigInteger, BigInteger> nextProbablePrime() {
        return new Function1<BigInteger, BigInteger>() {
            @Override
            public BigInteger call(BigInteger bigInteger) throws Exception {
                return bigInteger.nextProbablePrime();
            }
        };
    }

    public static Function1<Number, Number> nextPrime = new Function1<Number, Number>() {
        @Override
        public Number call(Number number) throws Exception {
            return nextPrime(number);
        }
    };

    public static Computation<Number> primes = computation(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 Function1<Number, Number> nextPrime() {
        return nextPrime;
    }

    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 <T> Operators<Number> operatorsFor(Class<T> numberClass) {
        return Unchecked.cast(internalOperatorsFor(numberClass));
    }

    private static <T> Operators<? extends Number> internalOperatorsFor(Class<T> numberClass) {
        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 class " + numberClass);
    }

    public static Operators<Number> operatorsFor(Number number) {
        return operatorsFor(number.getClass());
    }

    public static Operators<Number> operatorsFor(Number a, Number b) {
        Operators<Number> aOperators = operatorsFor(a.getClass());
        Operators<Number> bOperators = operatorsFor(b.getClass());

        return aOperators.priority() > bOperators.priority() ? aOperators : bOperators;
    }

    public static Number negate(Number value) {
        return operatorsFor(value).negate(value);
    }

    public static Function1<Number, Number> increment = new Function1<Number, Number>() {
        public Number call(Number number) throws Exception {
            return Numbers.increment(number);
        }
    };

    public static Function1<Number, Number> increment() {
        return increment;
    }

    public static Number increment(Number value) {
        return operatorsFor(value).increment(value);
    }

    public static Function1<Number, Number> decrement = new Function1<Number, Number>() {
        public Number call(Number number) throws Exception {
            return Numbers.decrement(number);
        }
    };

    public static Function1<Number, 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;
        else if (operators.lessThan(y, x))
            return 1;
        return 0;
    }

    public static Comparator<Number> ascending() {
        return new Comparator<Number>() {
            public int compare(Number x, Number y) {
                return Numbers.compare(x, y);
            }
        };
    }

    public static Comparator<Number> descending() {
        return new Comparator<Number>() {
            public int compare(Number x, Number y) {
                return Numbers.compare(y, x);
            }
        };
    }

    public static Function1<Iterable<Number>, Number> sumIterable() {
        return new Function1<Iterable<Number>, Number>() {
            public Number call(Iterable<Number> numbers) throws Exception {
                return Sequences.reduceLeft(numbers, sum());
            }
        };
    }

    public static Function2<Number, Number, Number> average() {
        return new Average();
    }

    public static final Sum sum = new Sum();
    public static final Sum Σ = sum;

    public static Function2<Number, Number, Number> sum() {
        return sum;
    }

    public static final Sum add = sum;

    public static Function2<Number, Number, Number> add() {
        return add;
    }

    public static Function1<Number, 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 Function2<Number, Number, Number> subtract = new Function2<Number, Number, Number>() {
        public Number call(Number a, Number b) {
            return Numbers.subtract(a, b);
        }
    };

    public static Function2<Number, Number, Number> subtract() {
        return subtract;
    }

    public static Function1<Number, 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 Function2<Number, Number, Number> multiply = new Function2<Number, Number, Number>() {
        public Number call(Number multiplicand, Number multiplier) throws Exception {
            return multiply(multiplicand, multiplier);
        }
    };

    public static Function2<Number, Number, Number> multiply() {
        return multiply;
    }

    public static Function2<Number, Number, Number> product = multiply;

    public static Function2<Number, Number, Number> product() {
        return product;
    }

    public static Function1<Number, Number> multiply(final Number multiplicand) {
        return Numbers.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 Function1<Number, Number> divide(final Number divisor) {
        return divide().flip().apply(divisor);
    }

    public static Function2<Number, Number, Number> divide = new Function2<Number, Number, Number>() {
        public Number call(Number dividend, Number divisor) throws Exception {
            return divide(dividend, divisor);
        }
    };

    public static Function2<Number, Number, Number> divide() {
        return divide;
    }

    public static Number quotient(Number x, Number y) {
        throwIfZero(y);
        return reduce(operatorsFor(x, y).quotient(x, y));
    }

    public static Function1<Number, Number> mod(final Number divisor) {
        return mod().apply(divisor);
    }

    public static Function2<Number, Number, Number> remainder = new Function2<Number, Number, Number>() {
        @Override
        public Number call(Number dividend, Number divisor) throws Exception {
            return remainder(dividend, divisor);
        }
    };

    public static Function2<Number, Number, Number> remainder() {
        return remainder;
    }

    public static Function2<Number, Number, Number> mod = remainder.flip();

    public static Function2<Number, Number, Number> mod() {
        return mod;
    }

    public static Function1<Number, 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 Function1<Number, Number> reduce() {
        return new Function1<Number, Number>() {
            @Override
            public Number call(Number number) throws Exception {
                return reduce(number);
            }
        };
    }

    public static Function1<Number, Character> toCharacter() {
        return new Function1<Number, Character>() {
            public Character call(Number number) throws Exception {
                return (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 Callable2<Number, Number, Number> maximum = new Callable2<Number, Number, Number>() {
        @Override
        public Number call(Number a, Number b) throws Exception {
            return compare(a, b) > 0 ? a : b;
        }
    };

    public static Callable2<Number, Number, Number> maximum() {
        return maximum;
    }

    public static Function2<Number, Number, Number> lcm = new Function2<Number, Number, Number>() {
        @Override
        public Number call(Number x, Number y) throws Exception {
            return lcm(x, y);
        }
    };

    public static Function2<Number, Number, Number> 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 Function2<Number, Number, Number> gcd() {
        return new Function2<Number, Number, Number>() {
            @Override
            public Number call(Number x, Number y) throws Exception {
                return gcd(x, y);
            }
        };
    }

    public static Number gcd(Number x, Number y) {
        return integralOperatorsFor(x, y).gcd(x, y);
    }
}
<commit_msg>Added basic squareRoot method and function<commit_after>/*
This code is a a heavily modified version of Numbers from Rich Hickeys clojure core
 */

/**
 *   Copyright (c) <NAME>. 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.Callable1;
import com.googlecode.totallylazy.Callable2;
import com.googlecode.totallylazy.Computation;
import com.googlecode.totallylazy.Function1;
import com.googlecode.totallylazy.Function2;
import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.Pair;
import com.googlecode.totallylazy.Predicate;
import com.googlecode.totallylazy.Predicates;
import com.googlecode.totallylazy.Segment;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.Sequences;
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.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.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 ArithmeticException DIVIDE_BY_ZERO = new ArithmeticException("Divide by zero");
    public static Function1<Number, Integer> intValue = new Function1<Number, Integer>() {
        @Override
        public Integer call(Number number) throws Exception {
            return 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) {
        if (lessThan(end, start)) return iterate(add(step), start).takeWhile(greaterThanOrEqualTo(end));
        return iterate(add(step), start).takeWhile(lessThanOrEqualTo(end));
    }

    public static Option<Number> valueOf(String string) {
        try {
            return some(reduce(new BigDecimal(string)));
        } catch (Exception e) {
            return none(Number.class);
        }
    }

    public static Callable1<Object, Number> valueOf = new Callable1<Object, Number>() {
        @Override
        public Number call(Object value) throws Exception {
            return 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 Function1<Number, Number> squareRoot = new Function1<Number, Number>() {
        @Override
        public Number call(Number number) throws Exception {
            return squareRoot(number);
        }
    };

    public static Function1<Number, Number> squared = new Function1<Number, Number>() {
        @Override
        public Number call(Number number) throws Exception {
            return squared(number);
        }
    };

    public static Function1<Number, 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 Function1<BigInteger, BigInteger> nextProbablePrime() {
        return new Function1<BigInteger, BigInteger>() {
            @Override
            public BigInteger call(BigInteger bigInteger) throws Exception {
                return bigInteger.nextProbablePrime();
            }
        };
    }

    public static Function1<Number, Number> nextPrime = new Function1<Number, Number>() {
        @Override
        public Number call(Number number) throws Exception {
            return nextPrime(number);
        }
    };

    public static Computation<Number> primes = computation(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 Function1<Number, Number> nextPrime() {
        return nextPrime;
    }

    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 <T> Operators<Number> operatorsFor(Class<T> numberClass) {
        return Unchecked.cast(internalOperatorsFor(numberClass));
    }

    private static <T> Operators<? extends Number> internalOperatorsFor(Class<T> numberClass) {
        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 class " + numberClass);
    }

    public static Operators<Number> operatorsFor(Number number) {
        return operatorsFor(number.getClass());
    }

    public static Operators<Number> operatorsFor(Number a, Number b) {
        Operators<Number> aOperators = operatorsFor(a.getClass());
        Operators<Number> bOperators = operatorsFor(b.getClass());

        return aOperators.priority() > bOperators.priority() ? aOperators : bOperators;
    }

    public static Number negate(Number value) {
        return operatorsFor(value).negate(value);
    }

    public static Function1<Number, Number> increment = new Function1<Number, Number>() {
        public Number call(Number number) throws Exception {
            return Numbers.increment(number);
        }
    };

    public static Function1<Number, Number> increment() {
        return increment;
    }

    public static Number increment(Number value) {
        return operatorsFor(value).increment(value);
    }

    public static Function1<Number, Number> decrement = new Function1<Number, Number>() {
        public Number call(Number number) throws Exception {
            return Numbers.decrement(number);
        }
    };

    public static Function1<Number, 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;
        else if (operators.lessThan(y, x))
            return 1;
        return 0;
    }

    public static Comparator<Number> ascending() {
        return new Comparator<Number>() {
            public int compare(Number x, Number y) {
                return Numbers.compare(x, y);
            }
        };
    }

    public static Comparator<Number> descending() {
        return new Comparator<Number>() {
            public int compare(Number x, Number y) {
                return Numbers.compare(y, x);
            }
        };
    }

    public static Function1<Iterable<Number>, Number> sumIterable() {
        return new Function1<Iterable<Number>, Number>() {
            public Number call(Iterable<Number> numbers) throws Exception {
                return Sequences.reduceLeft(numbers, sum());
            }
        };
    }

    public static Function2<Number, Number, Number> average() {
        return new Average();
    }

    public static final Sum sum = new Sum();
    public static final Sum Σ = sum;

    public static Function2<Number, Number, Number> sum() {
        return sum;
    }

    public static final Sum add = sum;

    public static Function2<Number, Number, Number> add() {
        return add;
    }

    public static Function1<Number, 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 Function2<Number, Number, Number> subtract = new Function2<Number, Number, Number>() {
        public Number call(Number a, Number b) {
            return Numbers.subtract(a, b);
        }
    };

    public static Function2<Number, Number, Number> subtract() {
        return subtract;
    }

    public static Function1<Number, 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 Function2<Number, Number, Number> multiply = new Function2<Number, Number, Number>() {
        public Number call(Number multiplicand, Number multiplier) throws Exception {
            return multiply(multiplicand, multiplier);
        }
    };

    public static Function2<Number, Number, Number> multiply() {
        return multiply;
    }

    public static Function2<Number, Number, Number> product = multiply;

    public static Function2<Number, Number, Number> product() {
        return product;
    }

    public static Function1<Number, Number> multiply(final Number multiplicand) {
        return Numbers.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 Function1<Number, Number> divide(final Number divisor) {
        return divide().flip().apply(divisor);
    }

    public static Function2<Number, Number, Number> divide = new Function2<Number, Number, Number>() {
        public Number call(Number dividend, Number divisor) throws Exception {
            return divide(dividend, divisor);
        }
    };

    public static Function2<Number, Number, Number> divide() {
        return divide;
    }

    public static Number quotient(Number x, Number y) {
        throwIfZero(y);
        return reduce(operatorsFor(x, y).quotient(x, y));
    }

    public static Function1<Number, Number> mod(final Number divisor) {
        return mod().apply(divisor);
    }

    public static Function2<Number, Number, Number> remainder = new Function2<Number, Number, Number>() {
        @Override
        public Number call(Number dividend, Number divisor) throws Exception {
            return remainder(dividend, divisor);
        }
    };

    public static Function2<Number, Number, Number> remainder() {
        return remainder;
    }

    public static Function2<Number, Number, Number> mod = remainder.flip();

    public static Function2<Number, Number, Number> mod() {
        return mod;
    }

    public static Function1<Number, 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 Function1<Number, Number> reduce() {
        return new Function1<Number, Number>() {
            @Override
            public Number call(Number number) throws Exception {
                return reduce(number);
            }
        };
    }

    public static Function1<Number, Character> toCharacter() {
        return new Function1<Number, Character>() {
            public Character call(Number number) throws Exception {
                return (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 Callable2<Number, Number, Number> maximum = new Callable2<Number, Number, Number>() {
        @Override
        public Number call(Number a, Number b) throws Exception {
            return compare(a, b) > 0 ? a : b;
        }
    };

    public static Callable2<Number, Number, Number> maximum() {
        return maximum;
    }

    public static Function2<Number, Number, Number> lcm = new Function2<Number, Number, Number>() {
        @Override
        public Number call(Number x, Number y) throws Exception {
            return lcm(x, y);
        }
    };

    public static Function2<Number, Number, Number> 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 Function2<Number, Number, Number> gcd() {
        return new Function2<Number, Number, Number>() {
            @Override
            public Number call(Number x, Number y) throws Exception {
                return gcd(x, y);
            }
        };
    }

    public static Number gcd(Number x, Number y) {
        return integralOperatorsFor(x, y).gcd(x, y);
    }
}

{'fraction_non_alphanumeric': 0.09840189029192815, 'fraction_numerical': 0.004624101222083894, 'mean_word_length': 2.9757575757575756, 'pattern_counts': {'":': 0, '<': 237, '<?xml version=': 0, '>': 241, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6955094', 'n_tokens_mistral': 10892, 'n_tokens_neox': 10407, 'n_words': 2949}