001: /*************************************************************************
002: * *
003: * 1) This source code file, in unmodified form, and compiled classes *
004: * derived from it can be used and distributed without restriction, *
005: * including for commercial use. (Attribution is not required *
006: * but is appreciated.) *
007: * *
008: * 2) Modified versions of this file can be made and distributed *
009: * provided: the modified versions are put into a Java package *
010: * different from the original package, edu.hws; modified *
011: * versions are distributed under the same terms as the original; *
012: * and the modifications are documented in comments. (Modification *
013: * here does not include simply making subclasses that belong to *
014: * a package other than edu.hws, which can be done without any *
015: * restriction.) *
016: * *
017: * David J. Eck *
018: * Department of Mathematics and Computer Science *
019: * Hobart and William Smith Colleges *
020: * Geneva, New York 14456, USA *
021: * Email: eck@hws.edu WWW: http://math.hws.edu/eck/ *
022: * *
023: *************************************************************************/package edu.hws.jcm.data;
024:
025: /**
026: * This class provides a few static functions for converting real numbers
027: * to strings and strings to real numbers. It should probalby be reimplemented
028: * to use the standard NumberFormat class for converting real to string.
029: */
030: public class NumUtils {
031:
032: /**
033: * Return the real number represented by the String s,
034: * or return Double.NaN if s does not represent a legal
035: * real number.
036: */
037: public static double stringToReal(String s) {
038: try {
039: Double d = new Double(s);
040: return d.doubleValue();
041: } catch (NumberFormatException e) {
042: return Double.NaN;
043: }
044: }
045:
046: /**
047: * Return a string representation of the real number
048: * x occupying, if possible, at most 10 spaces.
049: */
050: public static String realToString(double x) {
051: return realToString(x, 10);
052: }
053:
054: /**
055: * Goal is to return a reasonable string representation
056: * of x, using at most width spaces. (If the parameter width is
057: * unreasonably big or small, its value is adjusted to
058: * lie in the range 6 to 25.)
059: *
060: * @param x value to create string representation of.
061: * @param width maximum number of spaces used in string representation, if possible.
062: * @return a string representation for x. If x is Double.NaN, "undefined" is returned.
063: * If x is infinite, "INF" or "-INF" is returned.
064: */
065: public static String realToString(double x, int width) {
066: width = Math.min(25, Math.max(6, width));
067: if (Double.isNaN(x))
068: return "undefined";
069: if (Double.isInfinite(x))
070: if (x < 0)
071: return "-INF";
072: else
073: return "INF";
074: String s = String.valueOf(x);
075: if (Math.rint(x) == x && Math.abs(x) < 5e15
076: && s.length() <= (width + 2))
077: return String.valueOf((long) x); // return string without trailing ".0"
078: if (s.length() <= width)
079: return s;
080: boolean neg = false;
081: if (x < 0) {
082: neg = true;
083: x = -x;
084: width--;
085: s = String.valueOf(x);
086: }
087: long maxForNonExp = 5 * (long) Math.pow(10, width - 2);
088: if (x >= 0.0005 && x <= maxForNonExp
089: && (s.indexOf('E') == -1 && s.indexOf('e') == -1)) {
090: s = round(s, width);
091: s = trimZeros(s);
092: } else if (x > 1) { // construct exponential form with positive exponent
093: long power = (long) Math.floor(Math.log(x) / Math.log(10));
094: String exp = "E" + power;
095: int numlength = width - exp.length();
096: x = x / Math.pow(10, power);
097: s = String.valueOf(x);
098: s = round(s, numlength);
099: s = trimZeros(s);
100: s += exp;
101: } else { // constuct exponential form with negative argument
102: long power = (long) Math.ceil(-Math.log(x) / Math.log(10));
103: String exp = "E-" + power;
104: int numlength = width - exp.length();
105: x = x * Math.pow(10, power);
106: s = String.valueOf(x);
107: s = round(s, numlength);
108: s = trimZeros(s);
109: s += exp;
110: }
111: if (neg)
112: return "-" + s;
113: else
114: return s;
115: }
116:
117: private static String trimZeros(String num) {
118: // Helper function for realToString.
119: // Remove trailing zeros if num contains a decimal point, and
120: // remove the decimal point as well if all following digits are zero
121: if (num.indexOf('.') >= 0
122: && num.charAt(num.length() - 1) == '0') {
123: int i = num.length() - 1;
124: while (num.charAt(i) == '0')
125: i--;
126: if (num.charAt(i) == '.')
127: num = num.substring(0, i);
128: else
129: num = num.substring(0, i + 1);
130: }
131: return num;
132: }
133:
134: private static String round(String num, int length) {
135: // Helper function for realToString.
136: // Round off num to the given field width
137: if (num.indexOf('.') < 0)
138: return num;
139: if (num.length() <= length)
140: return num;
141: if (num.charAt(length) >= '5' && num.charAt(length) != '.') {
142: char[] temp = new char[length + 1];
143: int ct = length;
144: boolean rounding = true;
145: for (int i = length - 1; i >= 0; i--) {
146: temp[ct] = num.charAt(i);
147: if (rounding && temp[ct] != '.') {
148: if (temp[ct] < '9') {
149: temp[ct]++;
150: rounding = false;
151: } else
152: temp[ct] = '0';
153: }
154: ct--;
155: }
156: if (rounding) {
157: temp[ct] = '1';
158: ct--;
159: }
160: // ct is -1 or 0
161: return new String(temp, ct + 1, length - ct);
162: } else
163: return num.substring(0, length);
164: }
165:
166: } // end class NumUtils
|