com.feilong.core.lang.NumberUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.feilong.core.lang.NumberUtil.java

Source

/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.core.lang;

import static java.math.RoundingMode.HALF_UP;

import java.math.BigDecimal;
import java.math.RoundingMode;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

import com.feilong.core.NumberPattern;
import com.feilong.core.text.NumberFormatUtil;

import static com.feilong.core.bean.ConvertUtil.toBigDecimal;

/**
 * ?{@link Integer},{@link Long},{@link BigDecimal}?.
 * 
 * <h3>{@link RoundingMode#HALF_UP} {@link Math#round(double)}:</h3>
 * 
 * <blockquote>
 * <p style="color:red">
 * ?{@link RoundingMode#HALF_UP} -2.5 ??-3, {@link Math#round(double) Math.round(-2.5)} -2
 * </p>
 * </blockquote>
 * 
 * <h3>{@link Double}{@link BigDecimal}:</h3>
 * 
 * <blockquote>
 * <p>
 *  double ? BigDecimal,?? BigDecimal.valueOf(double),?new BigDecimal(double),?? JDK API
 * </p>
 * <ol>
 * <li>new BigDecimal(0.1) {@code ==>} 0.1000000000000000055511151231257827021181583404541015625</li>
 * <li>BigDecimal.valueOf(0.1) {@code ==>} 0.1</li>
 * </ol>
 * <p>
 * Effective Java??,floatdouble???,? {@link java.math.BigDecimal}.
 * </p>
 * </blockquote>
 * 
 * <h3><a name="RoundingMode">JAVA 8??:</a></h3>
 * 
 * <blockquote>
 * <table border="1" cellspacing="0" cellpadding="4" summary="">
 * <tr style="background-color:#ccccff">
 * <th align="left"></th>
 * <th align="left"></th>
 * </tr>
 * <tr valign="top">
 * <td>{@link RoundingMode#UP}</td>
 * <td>??. ????,?????0??.</td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@link RoundingMode#DOWN}</td>
 * <td>???,????,???,??.</td>
 * </tr>
 * <tr valign="top">
 * <td>{@link RoundingMode#CEILING}</td>
 * <td>??? ??? ???.<br>
 * ,?ROUND_UP,<br>
 * ,?ROUND_DOWN.<br>
 * <span style="color:red">Math.round()?.</span></td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@link RoundingMode#FLOOR}</td>
 * <td>??? ??? ???.<br>
 * ,?ROUND_DOWN;<br>
 * ,?ROUND_UP.</td>
 * </tr>
 * <tr valign="top">
 * <td>{@link RoundingMode#HALF_UP}</td>
 * <td>?,?.<br>
 * ?(5).<span style="color:red">??</span>.</td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@link RoundingMode#HALF_DOWN}</td>
 * <td>?,?(5?). 5??.</td>
 * </tr>
 * <tr valign="top">
 * <td>{@link RoundingMode#HALF_EVEN}</td>
 * <td>?,?. <br>
 * ?;?,??,?,??. <br>
 * ???1?,???: <br>
 * {@code 1.15  1.2} {@code 1.25   1.2}</td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@link RoundingMode#UNNECESSARY}</td>
 * <td>?</td>
 * </tr>
 * </table>
 * </blockquote>
 *
 * @author <a href="http://feitianbenyue.iteye.com/">feilong</a>
 * @see Integer
 * @see Long
 * @see BigDecimal
 * @see Number
 * @see NumberPattern
 * @see RoundingMode
 * @see org.apache.commons.lang3.math.NumberUtils
 * @since 1.4.0
 */
public final class NumberUtil {

    /** Don't let anyone instantiate this class. */
    private NumberUtil() {
        //AssertionError?. ?????. ???.
        //see Effective Java 2nd
        throw new AssertionError("No " + getClass().getName() + " instances for you!");
    }

    // [start]Divide

    /**
     * <code>one/two</code>,?{@link RoundingMode#HALF_UP},?? <code>scale</code> .
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * NumberUtil.getDivideValue(0, 2, 0)   =   0
     * NumberUtil.getDivideValue(6, 4, 0)   =   2
     * NumberUtil.getDivideValue(10, 3, 2)  =   3.33
     * NumberUtil.getDivideValue(5, 3, 2)   =   1.67
     * </pre>
     * 
     * </blockquote>
     * 
     * @param one
     *            
     * @param two
     *            ,?{@link BigDecimal}??
     * @param scale
     *            ,??,?,see {@link java.math.BigDecimal#setScale(int, RoundingMode)}
     * @return  <code>one</code>  null, {@link NullPointerException}<br>
     *          <code>two</code>  null, {@link NullPointerException}<br>
     *          <code>two</code>  0, {@link IllegalArgumentException}<br>
     *         ???{@link BigDecimal} one/two,? {@link RoundingMode#HALF_UP},?? <code>scale</code> 
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @see java.math.RoundingMode#HALF_UP
     * @see java.math.BigDecimal#ROUND_HALF_UP
     * @see #getDivideValue(Number, Number, int, RoundingMode)
     * @since 1.5.5
     */
    public static BigDecimal getDivideValue(Number one, Number two, int scale) {
        return getDivideValue(one, two, scale, HALF_UP);
    }

    /**
     * <code>one/two</code>,?? <code>roundingMode</code> ? ?? <code>scale</code>.
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * NumberUtil.getDivideValue(0, 2, 0,RoundingMode.HALF_UP)   =   0
     * NumberUtil.getDivideValue(6, 4, 0,RoundingMode.HALF_UP)   =   2
     * NumberUtil.getDivideValue(10, 3, 2,RoundingMode.HALF_UP)  =   3.33
     * NumberUtil.getDivideValue(5, 3, 2,RoundingMode.HALF_UP)   =   1.67
     * </pre>
     * 
     * </blockquote>
     * 
     * @param one
     *            
     * @param two
     *            ,?{@link BigDecimal}??
     * @param scale
     *            ,??,see {@link java.math.BigDecimal#setScale(int, RoundingMode)}
     * @param roundingMode
     *            ? {@link RoundingMode}
     * @return  <code>one</code>  null, {@link NullPointerException}<br>
     *          <code>two</code>  null, {@link NullPointerException}<br>
     *          <code>two</code>  0, {@link IllegalArgumentException}<br>
     *         ???{@link BigDecimal} one/two,??? <code>roundingMode</code>,?? <code>scale</code> 
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @see java.math.BigDecimal#divide(BigDecimal, int, RoundingMode)
     * @since 1.5.5
     */
    public static BigDecimal getDivideValue(Number one, Number two, int scale, RoundingMode roundingMode) {
        Validate.notNull(one, "one can't be null!");
        Validate.notNull(two, "two can't be null!");

        BigDecimal divisor = toBigDecimal(two);
        Validate.isTrue(!divisor.equals(new BigDecimal(0)), "two can't be zero!");

        // ?one.divide(two),scaleroundingMode,?????.
        // ?? exception:Non-terminating decimal expansion; no exact representable decimal result
        return toBigDecimal(one).divide(divisor, scale, roundingMode);
    }

    // [end]

    // [start]Multiply

    /**
     * ,?{@link BigDecimal}.
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * NumberUtil.getMultiplyValue(5, 2, 5)                         =   10.00000
     * NumberUtil.getMultiplyValue(new BigDecimal(6.25), 1.17, 5)   =   7.31250
     * </pre>
     * 
     * </blockquote>
     * 
     * @param one
     *            
     * @param two
     *            
     * @param scale
     *            ,??,?,see {@link java.math.BigDecimal#setScale(int, RoundingMode)}
     * @return  <code>one</code>  null, {@link NullPointerException}<br>
     *          <code>two</code>  null, {@link NullPointerException}<br>
     *         ? convert to {@link BigDecimal} and multiply each other
     * @see #setScale(BigDecimal, int)
     * @since 1.5.5
     */
    public static BigDecimal getMultiplyValue(Number one, Number two, int scale) {
        Validate.notNull(one, "one can't be null!");
        Validate.notNull(two, "two can't be null!");
        //: (this.scale() + multiplicand.scale()).
        BigDecimal multiplyValue = toBigDecimal(one).multiply(toBigDecimal(two));
        return setScale(multiplyValue, scale);
    }
    // [end]

    // [start]Add

    /**
     * ?.
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * NumberUtil.getAddValue(2, 4, 5)              =   11
     * NumberUtil.getAddValue(new BigDecimal(6), 5) =   11
     * </pre>
     * 
     * </blockquote>
     * 
     * @param numbers
     *            the numbers
     * @return  <code>numbers</code> null, {@link NullPointerException}<br>
     *         null, {@link IllegalArgumentException}<br>
     *         ????{@link BigDecimal},?
     * @since 1.5.5
     */
    public static BigDecimal getAddValue(Number... numbers) {
        Validate.noNullElements(numbers, "numbers can't be null!");

        BigDecimal sum = BigDecimal.ZERO;
        for (Number number : numbers) {
            sum = sum.add(toBigDecimal(number));
        }
        return sum;
    }

    // [end]

    /**
     * ?? ??? 0.0,0.5,1.0,1.5,2.0,2.5....
     * 
     * <p>
     *  
     * </p>
     *
     * @param value
     *            
     * @return  <code>value</code> null, {@link NullPointerException}
     */
    public static String toPointFive(Number value) {
        Validate.notNull(value, "value can't be null/empty!");

        long avgRankLong = Math.round(Double.parseDouble(value.toString()) * 2);
        BigDecimal avgBigDecimal = BigDecimal.valueOf((double) (avgRankLong) / 2);
        return setScale(avgBigDecimal, 1).toString();
    }

    /**
     * ?, {@link NumberFormatUtil#format(Number, String)} .
     * 
     * <h3>:</h3>
     * 
     * <pre class="code">
     * //?,??
     * NumberUtil.toString(0.24f, NumberPattern.PERCENT_WITH_NOPOINT)   = 24%
     * 
     * //?,??
     * NumberUtil.toString(0.24f, NumberPattern.PERCENT_WITH_2POINT)    = 24.00%
     * </pre>
     * 
     * @param value
     *            
     * @param numberPattern
     *             {@link NumberPattern}
     * @return  <code>value</code> null, {@link NullPointerException}<br>
     *          <code>numberPattern</code> null, {@link NullPointerException}<br>
     *          <code>numberPattern</code> blank, {@link IllegalArgumentException}<br>
     *         , {@link StringUtils#EMPTY}
     * @see NumberFormatUtil#format(Number, String)
     */
    public static String toString(Number value, String numberPattern) {
        return NumberFormatUtil.format(value, numberPattern);
    }

    // *****************************************************************************************************

    /**
     * ,? {@link NumberPattern#PERCENT_WITH_NOPOINT}.
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * <pre class="code">
     * NumberUtil.getProgress(2, 3)     = 67%
     * </pre>
     * 
     * </blockquote>
     *
     * @param current
     *            ??
     * @param total
     *            ?
     * @return  <code>current</code> null, {@link NullPointerException}<br>
     *          <code>total</code> null, {@link NullPointerException}<br>
     *          {@code current<=0}, {@link IllegalArgumentException}<br>
     *          {@code total<=0}, {@link IllegalArgumentException}<br>
     *          {@code current>total}, {@link IllegalArgumentException}<br>
     * @see NumberPattern#PERCENT_WITH_NOPOINT
     * @see #getProgress(Number, Number, String)
     * @since 1.0.7
     */
    public static String getProgress(Number current, Number total) {
        return getProgress(current, total, NumberPattern.PERCENT_WITH_NOPOINT);
    }

    /**
     * .
     * 
     * <pre class="code">
     * NumberUtil.getProgress(5, 5, NumberPattern.PERCENT_WITH_NOPOINT) =   100%
     * NumberUtil.getProgress(2, 3, NumberPattern.PERCENT_WITH_1POINT)  =   66.7%
     * </pre>
     *
     * @param current
     *            ??
     * @param total
     *            ?
     * @param numberPattern
     *            the number pattern {@link NumberPattern}
     * @return  <code>current</code> null, {@link NullPointerException}<br>
     *          <code>total</code> null, {@link NullPointerException}<br>
     *          {@code current<=0}, {@link IllegalArgumentException}<br>
     *          {@code total<=0}, {@link IllegalArgumentException}<br>
     *          {@code current>total}, {@link IllegalArgumentException}<br>
     * @see NumberPattern
     * @see #getDivideValue(Number, Number, int)
     * @since 1.0.7
     */
    public static String getProgress(Number current, Number total, String numberPattern) {
        Validate.notNull(current, "current can't be null/empty!");
        Validate.notNull(total, "total can't be null/empty!");

        Validate.isTrue(current.intValue() > 0, "current can not <=0");
        Validate.isTrue(total.intValue() > 0, "total can not <=0");
        Validate.isTrue(current.doubleValue() <= total.doubleValue(), "current can not > total");

        // XXX  scale = 8?
        int scale = 8;
        BigDecimal bigDecimalCurrent = toBigDecimal(current);
        BigDecimal divideValue = getDivideValue(bigDecimalCurrent, total, scale);
        return toString(divideValue, numberPattern);
    }

    /**
     * ? {@link RoundingMode#HALF_UP},?,?.
     * 
     * <p style="color:red">
     * ?{@link RoundingMode#HALF_UP} -2.5 ??-3, {@link Math#round(double) Math.round(-2.5)} -2
     * </p>
     *
     * @param value
     *            the value
     * @return  <code>value</code> null, {@link NullPointerException}<br>
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @see #toNoScale(Number, RoundingMode)
     */
    public static BigDecimal toNoScale(Number value) {
        return toNoScale(value, HALF_UP);
    }

    /**
     * ?,?.
     * 
     * <p style="color:red">
     * ?:{@link RoundingMode#HALF_UP} -2.5 ??-3, {@link Math#round(double) Math.round(-2.5)} -2
     * </p>
     * 
     * @param value
     *            the value
     * @param roundingMode
     *            ? {@link RoundingMode}
     * @return  <code>value</code> null, {@link NullPointerException}<br>
     *          <code>roundingMode</code> null, {@link NullPointerException}<br>
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @since 1.5.5
     */
    public static BigDecimal toNoScale(Number value, RoundingMode roundingMode) {
        Validate.notNull(value, "value can't be null!");
        Validate.notNull(roundingMode, "roundingMode can't be null!");

        //int?long?double?stringBigDecimal.
        //double?,BigDecimal,String??.
        return setScale(toBigDecimal(value), 0, roundingMode);
    }

    //************************************************************************************************

    /**
     * ? ??? {@link RoundingMode#HALF_UP} ??.
     * 
     * <p>
     * ?>=0.5? ??<br>
     * </p>
     * 
     * <p style="color:red">
     * ?{@link RoundingMode#HALF_UP} -2.5 ??-3, Math.round(-2.5) -2
     * </p>
     * 
     * @param value
     *            number
     * @param scale
     *            ,??,?,see {@link java.math.BigDecimal#setScale(int, RoundingMode)}
     * @return  <code>value</code> null, {@link NullPointerException}<br>
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @see java.math.RoundingMode#HALF_UP
     * @see java.math.BigDecimal#ROUND_HALF_UP
     */
    private static BigDecimal setScale(BigDecimal value, int scale) {
        return setScale(value, scale, HALF_UP);
    }

    /**
     * .
     * 
     * @param value
     *            number
     * @param scale
     *            ,??,see {@link java.math.BigDecimal#setScale(int, RoundingMode)}
     * @param roundingMode
     *            ? {@link RoundingMode} ?:<a href="#RoundingMode">JAVA 8??</a>
     * @return  <code>value</code> null, {@link NullPointerException}<br>
     *          <code>roundingMode</code>null, {@link NullPointerException}
     * @see <a href="#RoundingMode">JAVA 8??</a>
     */
    private static BigDecimal setScale(BigDecimal value, int scale, RoundingMode roundingMode) {
        Validate.notNull(value, "value can't be null!");
        Validate.notNull(roundingMode, "roundingMode can't be null!");
        return value.setScale(scale, roundingMode);
    }
}