001: // Copyright (c) 1997, 2004, 2006 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.math;
005:
006: import java.math.BigDecimal;
007:
008: public abstract class RealNum extends Complex
009: /* #ifdef JAVA2 */
010: implements Comparable
011: /* #endif */
012: {
013: public final RealNum re() {
014: return this ;
015: }
016:
017: public final RealNum im() {
018: return IntNum.zero();
019: }
020:
021: public abstract boolean isNegative();
022:
023: /** Return 1 if >0; 0 if ==0; -1 if <0; -2 if NaN. */
024: public abstract int sign();
025:
026: public RealNum max(RealNum x) {
027: boolean exact = isExact() && x.isExact();
028: RealNum result = grt(x) ? this : x;
029: if (!exact && result.isExact())
030: result = new DFloNum(result.doubleValue());
031: return result;
032: }
033:
034: public RealNum min(RealNum x) {
035: boolean exact = isExact() && x.isExact();
036: RealNum result = grt(x) ? x : this ;
037: if (!exact && result.isExact())
038: result = new DFloNum(result.doubleValue());
039: return result;
040: }
041:
042: public static RealNum add(RealNum x, RealNum y, int k) {
043: return (RealNum) (x.add(y, k));
044: }
045:
046: public static RealNum times(RealNum x, RealNum y) {
047: return (RealNum) (x.mul(y));
048: }
049:
050: public static RealNum divide(RealNum x, RealNum y) {
051: return (RealNum) (x.div(y));
052: }
053:
054: /* These are defined in Complex, but have to be overridden. */
055: public abstract Numeric add(Object obj, int k);
056:
057: public abstract Numeric mul(Object obj);
058:
059: public abstract Numeric div(Object obj);
060:
061: public Numeric abs() {
062: return isNegative() ? neg() : this ;
063: }
064:
065: public final RealNum rneg() {
066: return (RealNum) neg();
067: }
068:
069: public boolean isZero() {
070: return sign() == 0;
071: }
072:
073: /** Convert to an exact number.
074: * Implements the Scheme inexact->exact (for real numbers).
075: */
076: public RatNum toExact() {
077: return DFloNum.toExact(doubleValue());
078: }
079:
080: /** Converts a real to an integer, according to a specified rounding mode.
081: * Note an inexact argument gives an inexact result, following Scheme.
082: * See also RatNum.toExactInt. */
083: public static double toInt(double d, int rounding_mode) {
084: switch (rounding_mode) {
085: case FLOOR:
086: return Math.floor(d);
087: case CEILING:
088: return Math.ceil(d);
089: case TRUNCATE:
090: return d < 0.0 ? Math.ceil(d) : Math.floor(d);
091: case ROUND:
092: return Math.rint(d);
093: default: // Illegal rounding_mode
094: return d;
095: }
096: }
097:
098: /** Converts a real to an integer, according to a specified rounding mode.
099: * Note an inexact argument gives an inexact result, following Scheme.
100: * See also toExactInt. */
101: public RealNum toInt(int rounding_mode) {
102: return new DFloNum(toInt(doubleValue(), rounding_mode));
103: }
104:
105: /** Converts to an exact integer, with specified rounding mode. */
106: public IntNum toExactInt(int rounding_mode) {
107: return toExactInt(doubleValue(), rounding_mode);
108: }
109:
110: /** Converts real to an exact integer, with specified rounding mode. */
111: public static IntNum toExactInt(double value, int rounding_mode) {
112: return toExactInt(toInt(value, rounding_mode));
113: }
114:
115: /** Converts an integral double (such as a toInt result) to an IntNum. */
116: public static IntNum toExactInt(double value) {
117: if (Double.isInfinite(value) || Double.isNaN(value))
118: throw new ArithmeticException("cannot convert " + value
119: + " to exact integer");
120: long bits = Double.doubleToLongBits(value);
121: boolean neg = bits < 0;
122: int exp = (int) (bits >> 52) & 0x7FF;
123: bits &= 0xfffffffffffffL;
124: if (exp == 0)
125: bits <<= 1;
126: else
127: bits |= 0x10000000000000L;
128: if (exp <= 1075) {
129: int rshift = 1075 - exp;
130: if (rshift > 53)
131: return IntNum.zero();
132: bits >>= rshift;
133: return IntNum.make(neg ? -bits : bits);
134: }
135: return IntNum
136: .shift(IntNum.make(neg ? -bits : bits), exp - 1075);
137: }
138:
139: public Complex exp() {
140: return new DFloNum(Math.exp(doubleValue()));
141: }
142:
143: public Complex log() {
144: double x = doubleValue();
145: if (x < 0)
146: return DComplex.log(x, 0.0);
147: return new DFloNum(Math.log(x));
148: }
149:
150: public final Complex sin() {
151: return new DFloNum(Math.sin(doubleValue()));
152: }
153:
154: public final Complex sqrt() {
155: double d = doubleValue();
156: if (d >= 0)
157: return new DFloNum(Math.sqrt(d));
158: else
159: return DComplex.sqrt(d, 0);
160: }
161:
162: /** Convert double to (rounded) integer, after multiplying by 10**k. */
163: public static IntNum toScaledInt(double f, int k) {
164: return toScaledInt(DFloNum.toExact(f), k);
165: }
166:
167: /** Convert rational to (rounded) integer, after multiplying by 10**k. */
168: public static IntNum toScaledInt(RatNum r, int k) {
169: if (k != 0) {
170: IntNum power = IntNum.power(IntNum.ten(), k < 0 ? -k : k);
171: IntNum num = r.numerator();
172: IntNum den = r.denominator();
173: if (k >= 0)
174: num = IntNum.times(num, power);
175: else
176: den = IntNum.times(den, power);
177: r = RatNum.make(num, den);
178: }
179: return r.toExactInt(ROUND);
180: }
181:
182: /** Convert this to (rounded) integer, after multiplying by 10**k. */
183: public IntNum toScaledInt(int k) {
184: return toScaledInt(toExact(), k);
185: }
186:
187: /*
188: public static String toScaledIntString (double f, int k)
189: {
190: switch (k)
191: {
192: case 0: break;
193: case 1: f = f * 10; break;
194: case 2: f = f * 100; break;
195: case 3: f = f * 1000; break;
196: default: return toScaledInt(f, k).toString();
197: }
198: return Long.toString((long) f);
199: }
200: */
201:
202: /** Implements the Comparable interface.
203: * This ordering isn't fully consistent with equals, since say
204: * it returns 0 when comparing 1.5 and 3/2, though they are not equals.
205: */
206: public int compareTo(Object o) {
207: return compare(o);
208: }
209:
210: public java.math.BigDecimal asBigDecimal() {
211: return new BigDecimal(doubleValue());
212: }
213:
214: public static String toStringScientific(float d) {
215: return toStringScientific(Float.toString(d));
216: }
217:
218: public static String toStringScientific(double d) {
219: return toStringScientific(Double.toString(d));
220: }
221:
222: /** Convert result of Double.toString or Float.toString to
223: * scientific notation.
224: * Does not validate the input.
225: */
226: public static String toStringScientific(String dstr) {
227: int indexE = dstr.indexOf('E');
228: if (indexE >= 0)
229: return dstr;
230: int len = dstr.length();
231: // Check for "Infinity" or "NaN".
232: char ch = dstr.charAt(len - 1);
233: if (ch == 'y' || ch == 'N')
234: return dstr;
235: StringBuffer sbuf = new StringBuffer(len + 10);
236: int exp = toStringScientific(dstr, sbuf);
237: sbuf.append('E');
238: sbuf.append(exp);
239: return sbuf.toString();
240: }
241:
242: public static int toStringScientific(String dstr, StringBuffer sbuf) {
243: boolean neg = dstr.charAt(0) == '-';
244: if (neg)
245: sbuf.append('-');
246: int pos = neg ? 1 : 0;
247: int exp;
248: int len = dstr.length();
249: if (dstr.charAt(pos) == '0') { // Value is < 1.0.
250: int start = pos;
251: for (;;) {
252: if (pos == len) {
253: sbuf.append("0");
254: exp = 0;
255: break;
256: }
257: char ch = dstr.charAt(pos++);
258: if (ch >= '0' && ch <= '9' && (ch != '0' || pos == len)) {
259: sbuf.append(ch);
260: sbuf.append('.');
261: exp = ch == '0' ? 0 : start - pos + 2;
262: if (pos == len)
263: sbuf.append('0');
264: else {
265: while (pos < len)
266: sbuf.append(dstr.charAt(pos++));
267: }
268: break;
269: }
270: }
271: } else {
272: // Number of significant digits in string.
273: int ndigits = len - (neg ? 2 : 1);
274: int dot = dstr.indexOf('.');
275: // Number of fractional digits is len-dot-1.
276: // We want ndigits-1 fractional digits. Hence we need to move the
277: // decimal point ndigits-1-(len-dot-1) == ndigits-len+dot positions
278: // to the left. This becomes the exponent we need.
279: exp = ndigits - len + dot;
280: sbuf.append(dstr.charAt(pos++)); // Copy initial digit before point.
281: sbuf.append('.');
282: while (pos < len) {
283: char ch = dstr.charAt(pos++);
284: if (ch != '.')
285: sbuf.append(ch);
286: }
287: }
288: // Remove excess zeros.
289: pos = sbuf.length();
290: int slen = -1;
291: for (;;) {
292: char ch = sbuf.charAt(--pos);
293: if (ch == '0')
294: slen = pos;
295: else {
296: if (ch == '.')
297: slen = pos + 2;
298: break;
299: }
300: }
301: if (slen >= 0)
302: sbuf.setLength(slen);
303: return exp;
304: }
305:
306: public static String toStringDecimal(String dstr) {
307: int indexE = dstr.indexOf('E');
308: if (indexE < 0)
309: return dstr;
310: int len = dstr.length();
311: // Check for "Infinity" or "NaN".
312: char ch = dstr.charAt(len - 1);
313: if (ch == 'y' || ch == 'N')
314: return dstr;
315: StringBuffer sbuf = new StringBuffer(len + 10);
316: boolean neg = dstr.charAt(0) == '-';
317: if (dstr.charAt(indexE + 1) != '-') {
318: throw new Error(
319: "not implemented: toStringDecimal given non-negative exponent: "
320: + dstr);
321: } else {
322: int pos = indexE + 2; // skip "E-".
323: int exp = 0;
324: while (pos < len)
325: exp = 10 * exp + (dstr.charAt(pos++) - '0');
326: if (neg)
327: sbuf.append('-');
328: sbuf.append("0.");
329: while (--exp > 0)
330: sbuf.append('0');
331: for (pos = 0; (ch = dstr.charAt(pos++)) != 'E';) {
332: if (ch != '-' & ch != '.'
333: && (ch != '0' || pos < indexE))
334: sbuf.append(ch);
335: }
336: return sbuf.toString();
337: }
338: }
339: }
|