All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.spardat.enterprise.util.NumberUtil Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
/*******************************************************************************
 * Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     s IT Solutions AT Spardat GmbH - initial API and implementation
 *******************************************************************************/

// @(#) $Id: NumberUtil.java 2582 2008-05-07 14:10:55Z webok $
package at.spardat.enterprise.util;

import java.math.BigDecimal;

/**
 * Provides some utility methods pertaining to numbers.
 */
public class NumberUtil {

    /**
     * Returned from method {@link #getMetric} to describe a canonic number
     */
    public final static class Metric {
        // 0 is there is no sign, 1 otherwise
        public byte  lenSign_;
        // number of digits before the decimal point
        public short lenVorKomma_;
        // number of leading zeros in the part before the decimal point (<= lenVorKomma_)
        public byte  lenZerosVK_;
        // 0 if there is no decimal point, 1 otherwise
        public byte  lenKomma_;
        // number of digits after the decimal point
        public short lenNachKomma_;
    }

    /**
     * Parses a provided number in the so called canonic number format and returns
     * some information about it. We consider a number encoding to be canonic
     * if it obeys the following syntax: An '-', followed by a sequence
     * of digits, followed by '.', followed by a sequence of digits. All components
     * are optional. At least one digit must be present.
     *
     * @param v the number. Must not be null.
     * @return a Metric object describing the number or null, if the number is
     *          not a canonic one.
     */
    public static Metric getMetric (String v) {
        Metric          m = new Metric(); // assume members are 0-initialized
        int             vLen = v.length();
        int             vIndex = 0;
        if (vLen == 0) return null;
        char            c = v.charAt(vIndex);
        // optionales Vorzeichen
        if (c == '-') { m.lenSign_ = 1; vIndex++; }
        // Vorkommateil
        boolean         leadingZeros = true;
        while (vIndex < vLen) {
            char        ch = v.charAt(vIndex);
            if (NumberUtil.isDigit(ch)) {
                m.lenVorKomma_++; vIndex++;
                if (leadingZeros) {
                    // falls leadingZeros true, werden leading zeros gez?hlt;
                    if (ch == '0') m.lenZerosVK_++;
                    else leadingZeros = false;
                }
            } else break;
        }
        // Dezimalpunkt
        if (vIndex < vLen && v.charAt(vIndex) == '.') { m.lenKomma_ = 1; vIndex++; }
        // Nachkommateil
        while (vIndex < vLen) {
            if (NumberUtil.isDigit(v.charAt(vIndex))) {
                m.lenNachKomma_++; vIndex++;
            } else break;
        }
        // Konsistent?
        if (vIndex != vLen || m.lenVorKomma_ + m.lenNachKomma_ == 0) {
            return null;
        }
        return m;
    }

    /**
     * Provides a fast but not locale independent implementation of numeric check.
     */
    public static boolean isDigit (char ch) {
        return ch <= '9' && ch >= '0';
    }

    /**
     * Converts a nonnegative integer to a string, left-pads with zeros up to
     * a given length and appends the result to a StringBuffer. 

* * This method is performance optimized for small numbers, i.e., numbers * less than 10000. * * @param i integer to be appended. Must not be negative. * @param minLen minimum length of appended zero praefixed string * @param toAppendTo StringBuffer where to append to */ public static void appendIntString (int i, int minLen, StringBuffer toAppendTo) { if (i < 100) { if (i < 10) { StringUtil.appendN ('0', minLen-1, toAppendTo); toAppendTo.append((char)(i+'0')); } else { char d1 = (char)((i%10)+'0'); i /= 10; char d2 = (char)(i+'0'); StringUtil.appendN ('0', minLen-2, toAppendTo); toAppendTo.append(d2); toAppendTo.append(d1); } } else if (i < 10000) { if (i < 1000) { char d1 = (char)((i%10)+'0'); i /= 10; char d2 = (char)((i%10)+'0'); i /= 10; char d3 = (char)(i+'0'); StringUtil.appendN ('0', minLen-3, toAppendTo); toAppendTo.append(d3); toAppendTo.append(d2); toAppendTo.append(d1); } else { char d1 = (char)((i%10)+'0'); i /= 10; char d2 = (char)((i%10)+'0'); i /= 10; char d3 = (char)((i%10)+'0'); i /= 10; char d4 = (char)(i+'0'); StringUtil.appendN ('0', minLen-4, toAppendTo); toAppendTo.append(d4); toAppendTo.append(d3); toAppendTo.append(d2); toAppendTo.append(d1); } } else { String iAsS = Integer.toString(i); StringUtil.appendN ('0', minLen - iAsS.length(), toAppendTo); toAppendTo.append(iAsS); } } /** * Converts a double to a fixed point number string using a point * as decimal separation character (canonic format, see above). * If the provided double is NaN or Infinity, the empty string is returned. * Digits after the comma are reduced so that the total number of * significant digits does not exceed 15 digits. * * @param d the input double * @return string in canonic format */ public static String double2String (double d) { if (Double.isInfinite(d) || Double.isNaN(d)) return ""; BigDecimal bd = new BigDecimal (d); String bdS = BigDecimalHelper.toPlainString(bd); Metric m = getMetric (bdS); // if the number of significant digits in the produced string is not // greater than 15, we accept it int digits = m.lenVorKomma_ + m.lenNachKomma_; if (digits <= 15) return bdS; // otherwise: if the excess number of significant digits // lies in the fractional part, which may be due to not // being able to exactly represent the floating point value decimally, // we round int maxAfterKomma = 15 - m.lenVorKomma_; if (maxAfterKomma >= 0 && maxAfterKomma < bd.scale()) { bd = bd.setScale(maxAfterKomma, BigDecimal.ROUND_HALF_UP); bdS = bd.toString(); if (bdS.indexOf('.') != -1) { // strip trailing zeros int i = bdS.length()-1; for (; i>=0; i--) { if (bdS.charAt(i) != '0') break; } // the character at index i is the last that must be retained bdS = bdS.substring(0, i+1); } } return bdS; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy