com.tinspx.util.base.NumberUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.tinspx.util.base.NumberUtils.java

Source

/* Copyright (C) 2013-2014 Ian Teune <ian.teune@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.tinspx.util.base;

import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
import com.google.common.collect.BoundType;
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Range;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.Nullable;
import lombok.NonNull;

/**
 * {@link Number} utility functions.
 * 
 * @author Ian
 */
public class NumberUtils {

    private static final int[] EMPTY_INT_ARRAY = new int[0];

    /**
     * Determines if the the two {@code Number}s are equal by first converting
     * them to either a {@link BigInteger} or a {@link BigDecimal} and then
     * comparing the Numbers. BigDecimal numbers are considered equal if
     * if {@link BigDecimal#compareTo(BigDecimal)} is 0.
     *
     * @param a the first Number to compare
     * @param b the second number to compare
     * @return true if the two Numbers are equal
     * @throws NullPointerException if either a or b is null
     */
    public static boolean numberEquals(Number a, Number b) {
        a = toBigNumber(a);
        b = toBigNumber(b);
        if (a instanceof BigDecimal) {
            return bigDecimalEquals((BigDecimal) a, b);
        } else if (b instanceof BigDecimal) {
            return bigDecimalEquals((BigDecimal) b, a);
        } else {
            return a.equals(b);
        }
    }

    static boolean bigDecimalEquals(BigDecimal a, Number b) {
        if (b instanceof BigDecimal) {
            return bigDecimalEquals(a, (BigDecimal) b);
        } else if (b instanceof BigInteger) {
            return bigDecimalEquals(a, new BigDecimal((BigInteger) b));
        } else {
            return false;
        }
    }

    static boolean bigDecimalEquals(BigDecimal a, BigDecimal b) {
        return a.compareTo(b) == 0;
    }

    /**
     * Converts the the Number {@code n} to either a {@link BigInteger} or a
     * {@link BigDecimal}, unless the Number is a Float/Double +/- Infinity or
     * NaN, in which case {@link Double#NaN}, {@link Double#POSITIVE_INFINITY},
     * or {@link Double#NEGATIVE_INFINITY} is returned. 
     *
     * @param n the Number to convert
     * @return the {@link BigInteger} or {@link BigDecimal} equivalent of
     * {@code n}
     */
    public static Number toBigNumber(Number n) {
        if (n instanceof BigDecimal || n instanceof BigInteger) {
            return n;
        }
        if (n instanceof Float) {
            if (((Float) n).isInfinite()) {
                return n.equals(Float.POSITIVE_INFINITY) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
            } else if (((Float) n).isNaN()) {
                return Double.NaN;
            } else {
                return new BigDecimal(n.toString());
            }
        }
        if (n instanceof Double) {
            if (((Double) n).isInfinite() || ((Double) n).isNaN()) {
                return n;
            } else {
                //had issues with BigDecimal.valueOf(double), so String constructor must be used
                return new BigDecimal(n.toString());
            }
        }
        if (n instanceof Integer || n instanceof Long || n instanceof Byte || n instanceof Short
                || n instanceof AtomicInteger || n instanceof AtomicLong) {
            return new BigInteger(n.toString());
        }
        return new BigDecimal(n.toString());
    }

    /**
     * {@code from} is inclusive, {@code to} is exclusive
     */
    public static ContiguousSet<Integer> asSet(int from, int to) {
        return asSet(Range.closedOpen(from, to));
    }

    public static ContiguousSet<Integer> asSet(Range<Integer> range) {
        return ContiguousSet.create(range, DiscreteDomain.integers());
    }

    public static int getRandomInt(Range<Integer> range, Random random) {
        int min = range.lowerEndpoint();
        if (range.lowerBoundType() == BoundType.OPEN) {
            min++;
        }
        int max = range.upperEndpoint();
        if (range.upperBoundType() == BoundType.CLOSED) {
            max++;
        }
        return random.nextInt(max - min) + min;
    }

    /**
     * Concatenates {@code a} and {@code b}. If either {@code a} or {@code b} is
     * null, it is treated as an empty array. The returned array be the same
     * reference as {@code a} or {@code b} (this will happen if one of the
     * arrays is null or empty). The returned array may be empty, but will never
     * be null.
     *
     * @param a the first array, {@code b} will be appended to the end of a
     * @param b the second array, {@code a} will be prepended to the beginning
     * of b
     * @return the non-null result of concatenating {@code b} to the end of
     * {@code a}
     */
    public static int[] concat(@Nullable int a[], @Nullable int b[]) {
        if (a == null || a.length == 0) {
            return MoreObjects.firstNonNull(b, EMPTY_INT_ARRAY);
        } else if (b == null || b.length == 0) {
            return a;
        }
        int c[] = Arrays.copyOf(a, a.length + b.length);
        System.arraycopy(b, 0, c, a.length, b.length);
        return c;
    }

    private static final Function<Number, Integer> INT_F = new Function<Number, Integer>() {
        @Override
        public Integer apply(Number input) {
            if (input == null) {
                return null;
            }
            return input instanceof Integer ? (Integer) input : input.intValue();
        }
    };

    private static final Function<Number, Long> LONG_F = new Function<Number, Long>() {
        @Override
        public Long apply(Number input) {
            if (input == null) {
                return null;
            }
            return input instanceof Long ? (Long) input : input.longValue();
        }
    };

    private static final Function<Number, Float> FLOAT_F = new Function<Number, Float>() {
        @Override
        public Float apply(Number input) {
            if (input == null) {
                return null;
            }
            return input instanceof Float ? (Float) input : input.floatValue();
        }
    };

    private static final Function<Number, Double> Double_F = new Function<Number, Double>() {
        @Override
        public Double apply(Number input) {
            if (input == null) {
                return null;
            }
            return input instanceof Double ? (Double) input : input.doubleValue();
        }
    };

    public static Function<Number, Integer> intValue() {
        return INT_F;
    }

    public static Function<Number, Long> longValue() {
        return LONG_F;
    }

    public static Function<Number, Float> floatValue() {
        return FLOAT_F;
    }

    public static Function<Number, Double> doubleValue() {
        return Double_F;
    }

    @SuppressWarnings("unchecked")
    public static Range<Long> toLongRange(@NonNull Range<? extends Number> range) {
        if (range.hasLowerBound()) {
            if (range.hasUpperBound()) {
                if (range.lowerEndpoint() instanceof Long && range.upperEndpoint() instanceof Long) {
                    return (Range<Long>) range;
                }
                return Range.range(range.lowerEndpoint().longValue(), range.lowerBoundType(),
                        range.upperEndpoint().longValue(), range.upperBoundType());
            } else {
                if (range.lowerEndpoint() instanceof Long) {
                    return (Range<Long>) range;
                }
                return Range.downTo(range.lowerEndpoint().longValue(), range.lowerBoundType());
            }
        } else if (range.hasUpperBound()) {
            if (range.upperEndpoint() instanceof Long) {
                return (Range<Long>) range;
            }
            return Range.upTo(range.upperEndpoint().longValue(), range.upperBoundType());
        } else {
            return Range.all();
        }
    }

    @SuppressWarnings("rawtypes")
    public static <F extends Comparable, T extends Comparable> Range<T> transform(@NonNull Range<F> range,
            @NonNull Function<? super F, ? extends T> function) {
        if (range.hasLowerBound()) {
            if (range.hasUpperBound()) {
                return Range.range(function.apply(range.lowerEndpoint()), range.lowerBoundType(),
                        function.apply(range.upperEndpoint()), range.upperBoundType());
            } else {
                return Range.downTo(function.apply(range.lowerEndpoint()), range.lowerBoundType());
            }
        } else if (range.hasUpperBound()) {
            return Range.upTo(function.apply(range.upperEndpoint()), range.upperBoundType());
        } else {
            return Range.all();
        }
    }
}