com.adobe.xfa.ut.Numeric Maven / Gradle / Ivy
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2005 Adobe Systems Incorporated All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual and
* technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or copyright
* law. Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained from
* Adobe Systems Incorporated.
*/
package com.adobe.xfa.ut;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Locale;
/**
*
* @exclude from published api -- Mike Tardif, May 2006.
*/
public final class Numeric {
private final static int MAX_PRECISION = 15;
/*
* Disallow instances of this class.
*/
private Numeric() {
// empty
}
private final static NumberFormat format;
static {
format = NumberFormat.getNumberInstance(Locale.US);
format.setGroupingUsed(false);
format.setMinimumIntegerDigits(1);
format.setMaximumIntegerDigits(310);
}
//Bug#3018085: Define double to String conversion using BigDecimal
/**
* Format a double as a string using BigDecimal
* @param dValue - the double value
* @param fracDigits - the number of fractional digits to render
* @return the formatted string
*/
public static String doubleToStringUsingBigDecimal(double dValue, int fracDigits, boolean bTruncate /* = false */) {
if (Double.isNaN(dValue) || Double.isInfinite(dValue))
return "";
if (fracDigits >= 0) {
if (fracDigits > MAX_PRECISION)
fracDigits = MAX_PRECISION;
double fraction = dValue - (int)dValue;
int checkDigit = (int)(fraction * Math.pow(10.0, fracDigits + 1)) - (int)(fraction * Math.pow(10.0, fracDigits)) * 10;
if (checkDigit == 5)
dValue += Math.pow(0.1, fracDigits + 1);
// Javaport: Java doesn't round when formatting, so we have to do it explicitly.
// TODO: Minimize the use of Math.pow()
double p = Math.pow(10.0, fracDigits);
String conversionString = "%#." + fracDigits + "f";
if (fracDigits == 0) conversionString = "%.0f";
String sValue = String.format(conversionString, new BigDecimal(dValue));
if (!bTruncate)
return sValue;
if (sValue.charAt(sValue.length() - 1) != '0')
return sValue;
int endIndex = sValue.length() - 1;
while (sValue.charAt(endIndex) == '0')
endIndex--;
if (sValue.charAt(endIndex) == '.')
endIndex--;
return sValue.substring(0, endIndex + 1);
}
else {
String sValue = getNumberFormat(fracDigits).format(dValue);
return sValue;
}
}
/**
* Format a double as a string
* @param dValue - the double value
* @param fracDigits - the number of fractional digits to render
* @return the formatted string
*/
public static String doubleToString(double dValue, int fracDigits, boolean bTruncate /* = false */) {
if (Double.isNaN(dValue) || Double.isInfinite(dValue))
return "";
if (fracDigits >= 0) {
if (fracDigits > MAX_PRECISION)
fracDigits = MAX_PRECISION;
double fraction = dValue - (int)dValue;
int checkDigit = (int)(fraction * Math.pow(10.0, fracDigits + 1)) - (int)(fraction * Math.pow(10.0, fracDigits)) * 10;
if (checkDigit == 5)
dValue += Math.pow(0.1, fracDigits + 1);
// Javaport: Java doesn't round when formatting, so we have to do it explicitly.
// TODO: Minimize the use of Math.pow()
double p = Math.pow(10.0, fracDigits);
String conversionString = "%#." + fracDigits + "f";
if (fracDigits == 0) conversionString = "%.0f";
String sValue = String.format(conversionString, dValue);
if (!bTruncate)
return sValue;
if (sValue.charAt(sValue.length() - 1) != '0')
return sValue;
int endIndex = sValue.length() - 1;
while (sValue.charAt(endIndex) == '0')
endIndex--;
if (sValue.charAt(endIndex) == '.')
endIndex--;
return sValue.substring(0, endIndex + 1);
}
else {
String sValue = getNumberFormat(fracDigits).format(dValue);
return sValue;
}
}
public static double stringToDouble(String str, boolean bAllowNaN /* = false */) {
str = str.trim();
if (str.length() == 0)
return bAllowNaN ? Double.NaN : 0f;
ParsePosition pp = new ParsePosition(0);
// The number of fractional digits on the format used to parse is ignored.
Number n = getNumberFormat(1).parse(str, pp);
// Must not be errors and the entire input string must be consumed
if (n == null || pp.getErrorIndex() != -1 || pp.getIndex() < str.length()) {
return bAllowNaN ? Double.NaN : 0f;
}
double d = n.doubleValue();
if (Double.isNaN(d) || Double.isInfinite(d)) {
return bAllowNaN ? Double.NaN : 0f;
}
return d;
}
private static NumberFormat getNumberFormat(int fracDigits) {
// Number format objects are not synchronized, so we can't
// share instances across threads. To minimize the overhead
// of creating a new instance each time we format a number,
// keep a partially initialized instance that can be cloned
// each time it is used.
NumberFormat customFormat = (NumberFormat)format.clone();
customFormat.setMinimumFractionDigits(fracDigits);
customFormat.setMaximumFractionDigits(fracDigits);
return customFormat;
}
}