KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > math > ExponentialFormat


1 // Copyright (c) 1999 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.math;
5 import java.text.FieldPosition JavaDoc;
6
7 /** Format a real number using a floating-point format.
8  * However, if `general' is true, and the number "fits",
9  * use a fixed-point format (like printf %g).
10  * Used for Common Lisp specs ~E and ~G; also C-style %e and %g.
11  */

12
13 public class ExponentialFormat extends java.text.Format JavaDoc
14 {
15   /** Number of fractional digits to show.
16    * This is `d' in the CommonLisp spec. */

17   public int fracDigits = -1;
18
19   /** Number of digits to show in the integer part of the result.
20    * If positive, The number of digits before the decimal point.
21    * If negative, the -intDigits zeros are emitted after the decimal point.
22   * This is `k' in the CommonLisp spec. */

23   public int intDigits;
24
25   /** Number of digits to show in the exponent.
26    * Zero means unspecified - show as many as needed. */

27   public int expDigits;
28
29   public char overflowChar;
30   public char padChar;
31   public char exponentChar = 'E';
32   /** Display sign of exponent even when it is non-negative. */
33   public boolean exponentShowSign;
34
35   /** True if '+' should be printed for non-negative number. */
36   public boolean showPlus;
37
38   public int width;
39   public boolean general;
40
41   static final double LOG10 = Math.log(10);
42
43   /** Add 1 to the integer in sbuf from digStart to digEnd.
44    * @return if we overflowed. */

45   static boolean addOne(StringBuffer JavaDoc sbuf, int digStart, int digEnd)
46   {
47     for (int j = digEnd ; ; )
48       {
49     if (j == digStart)
50       {
51         sbuf.insert(j, '1');
52         return true;
53       }
54     char ch = sbuf.charAt(--j);
55     if (ch != '9')
56       {
57         sbuf.setCharAt(j, (char)((int) ch+1));
58         return false;
59       }
60     sbuf.setCharAt(j, '0');
61       }
62   }
63
64   public StringBuffer JavaDoc format(float value,
65                  StringBuffer JavaDoc sbuf, FieldPosition JavaDoc fpos)
66   {
67     return format(value, fracDigits < 0 ? Float.toString(value) : null,
68                   sbuf, fpos);
69   }
70
71   public StringBuffer JavaDoc format(double value,
72                  StringBuffer JavaDoc sbuf, FieldPosition JavaDoc fpos)
73   {
74     return format(value, fracDigits < 0 ? Double.toString(value) : null,
75                   sbuf, fpos);
76   }
77
78   StringBuffer JavaDoc format(double value, String JavaDoc dstr,
79                       StringBuffer JavaDoc sbuf, FieldPosition JavaDoc fpos)
80   {
81     int k = intDigits;
82     int d = fracDigits;
83     boolean negative = value < 0;
84     if (negative)
85       value = -value;
86     int oldLen = sbuf.length();
87     int signLen = 1;
88     if (negative)
89       {
90         if (d >= 0)
91           sbuf.append('-');
92         // Otherwise emitted by RealNum.toStringScientific.
93
}
94     else if (showPlus)
95       sbuf.append('+');
96     else
97       signLen = 0;
98     // Number of significant digits.
99
int digits, scale;
100     int digStart = sbuf.length();
101     int exponent;
102     boolean nonFinite = Double.isNaN(value) || Double.isInfinite(value);
103     if (d < 0 || nonFinite)
104       {
105     if (dstr == null)
106       dstr = Double.toString(value); // Needed if nonFinite && d >= 0.
107
int indexE = dstr.indexOf('E');
108         if (indexE >= 0)
109           {
110             sbuf.append(dstr);
111             indexE += digStart;
112             boolean negexp = dstr.charAt(indexE+1) == '-';
113             exponent = 0;
114             for (int i = indexE + (negexp ? 2 : 1); i < sbuf.length(); i++)
115               exponent = 10 * exponent + (sbuf.charAt(i) - '0');
116             if (negexp)
117               exponent = -exponent;
118             sbuf.setLength(indexE);
119           }
120         else
121           exponent = RealNum.toStringScientific(dstr, sbuf);
122         if (negative)
123           digStart++;
124         int dot = digStart + 1;
125         /* #ifdef JAVA2 */
126         sbuf.deleteCharAt(dot);
127         /* #else */
128         // String afterDot = sbuf.toString().substring(dot+1);
129
// sbuf.setLength(dot);
130
// sbuf.append(afterDot);
131
/* #endif */
132         digits = sbuf.length() - digStart;
133         // Remove trailing '0' added by RealNum.toStringScientific.
134
if (digits > 1 && sbuf.charAt(digStart+digits-1) == '0')
135           sbuf.setLength(digStart + --digits);
136         scale = digits - exponent - 1;
137       }
138     else
139       {
140         digits = d + (k > 0 ? 1 : k);
141         int log = (int) (Math.log(value) / LOG10 + 1000.0); // floor
142
if (log == 0x80000000) // value is zero
143
log = 0;
144         else
145           log = log - 1000;
146         scale = digits - log - 1;
147         RealNum.toScaledInt(value, scale).format(10, sbuf);
148         exponent = digits - 1 - scale;
149       }
150
151     exponent -= k - 1;
152     int exponentAbs = exponent < 0 ? -exponent : exponent;
153     int exponentLen = exponentAbs >= 1000 ? 4 : exponentAbs >= 100 ? 3
154       : exponentAbs >= 10 ? 2 : 1;
155     if (expDigits > exponentLen)
156       exponentLen = expDigits;
157     boolean showExponent = true;
158     int ee = !general ? 0 : expDigits > 0 ? expDigits + 2 : 4;
159     boolean fracUnspecified = d < 0;
160     if (general || fracUnspecified)
161       {
162     int n = digits - scale;
163     if (fracUnspecified)
164       {
165         d = n < 7 ? n : 7;
166         if (digits > d)
167           d = digits;
168       }
169     int dd = d - n;
170     if (general && (n >= 0 && dd >= 0))
171       {
172         // "arg is printed as if by the format directives
173
// ~ww,dd,0,overflowchar,padcharF~ee@T "
174
digits = d;
175         k = n;
176         showExponent = false;
177       }
178     else if (fracUnspecified)
179       {
180         if (width <= 0)
181           digits = d;
182         else
183           {
184                 int avail = width - signLen - exponentLen - 3;
185         digits = avail;
186         if (k < 0)
187           digits -= k;
188         if (digits > d)
189           digits = d;
190           }
191         if (digits <= 0)
192           digits = 1;
193       }
194       }
195
196     int digEnd = digStart + digits;
197     while (sbuf.length() < digEnd)
198       sbuf.append('0');
199
200     // Now round to specified digits.
201
char nextDigit = digEnd == sbuf.length() ? '0' : sbuf.charAt(digEnd);
202     boolean addOne = nextDigit >= '5';
203     // || (nextDigit == '5'
204
// && (Character.digit(sbuf.charAt(digEnd-1), 10) & 1) == 0);
205
if (addOne && addOne(sbuf, digStart, digEnd))
206       scale++;
207     // Truncate excess digits, after adjusting scale accordingly.
208
scale -= sbuf.length() - digEnd;
209     sbuf.setLength(digEnd);
210
211     int dot = digStart;
212     if (k < 0)
213       {
214     // Insert extra zeros after '.'.
215
for (int j = k; ++j <= 0; )
216       sbuf.insert(digStart, '0');
217       }
218     else
219       {
220     // Insert extra zeros before '.', if needed.
221
for (; digStart+k > digEnd; digEnd++)
222       sbuf.append('0');
223         dot += k;
224       }
225     if (nonFinite)
226       showExponent = false;
227     else
228       sbuf.insert(dot, '.');
229
230     int newLen, i;
231     if (showExponent)
232       {
233     // Append the exponent.
234
sbuf.append(exponentChar);
235         if (exponentShowSign || exponent < 0)
236           sbuf.append(exponent >= 0 ? '+' : '-');
237     i = sbuf.length();
238     sbuf.append(exponentAbs);
239     newLen = sbuf.length();
240     int j = expDigits - (newLen - i);
241     if (j > 0)
242       { // Insert extra exponent digits.
243
newLen += j;
244         while (--j >= 0)
245           sbuf.insert(i, '0');
246       }
247       }
248     else
249       {
250         exponentLen = 0;
251       }
252     newLen = sbuf.length();
253     int used = newLen - oldLen;
254     i = width - used;
255
256     // Insert '0' after '.' if needed and there is space.
257
if (fracUnspecified
258         && (dot + 1 == sbuf.length() || sbuf.charAt(dot+1) == exponentChar)
259         && (width <= 0 || i > 0))
260       {
261         i--;
262         sbuf.insert(dot+1, '0');
263       }
264
265     if ((i >= 0 || width <= 0)
266     && ! (showExponent && exponentLen > expDigits
267           && expDigits > 0 && overflowChar != '\0'))
268       {
269     // Insert optional '0' before '.' if there is space.
270
if (k <= 0 && (i > 0 || width <= 0))
271       {
272         sbuf.insert(digStart, '0');
273         --i;
274       }
275         if (! showExponent
276             // The CommonLisp spec requires adding spaces on the right
277
// when a ~g format ends up using fixed-point format, corresponding
278
// to the space otherwise used for the exponent. However, it seems
279
// wrong to do so when using a variable-width format.
280
&& width > 0)
281           {
282             for (; --ee >= 0; --i) // && sbuf.length() < oldLen + width; --i)
283
sbuf.append(' ');
284           }
285     // Insert padding:
286
while (--i >= 0)
287       sbuf.insert(oldLen, padChar);
288       }
289     else if (overflowChar != '\0')
290       {
291     sbuf.setLength(oldLen);
292     for (i = width; --i >= 0; )
293       sbuf.append(overflowChar);
294      }
295     return sbuf;
296   }
297
298   public StringBuffer JavaDoc format(long num, StringBuffer JavaDoc sbuf, FieldPosition JavaDoc fpos)
299   {
300     return format((double) num, sbuf, fpos);
301   }
302
303   public StringBuffer JavaDoc format(Object JavaDoc num, StringBuffer JavaDoc sbuf, FieldPosition JavaDoc fpos)
304   {
305     // Common Lisp says if value is non-real, print as if with ~wD. FIXME.
306
return format(((RealNum) num).doubleValue(), sbuf, fpos);
307   }
308
309   public java.lang.Number JavaDoc parse(String JavaDoc text, java.text.ParsePosition JavaDoc status)
310   {
311     throw new Error JavaDoc("ExponentialFormat.parse - not implemented");
312   }
313   public Object JavaDoc parseObject(String JavaDoc text, java.text.ParsePosition JavaDoc status)
314   {
315     throw new Error JavaDoc("ExponentialFormat.parseObject - not implemented");
316   }
317
318 }
319
Popular Tags