001: // Copyright (c) 1997 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.io.*;
007:
008: public class DFloNum extends RealNum implements Externalizable {
009: double value;
010:
011: public DFloNum() {
012: }
013:
014: public DFloNum(double value) {
015: this .value = value;
016: }
017:
018: public DFloNum(String s) throws NumberFormatException {
019: Double d = Double.valueOf(s); // wasteful ...
020: value = d.doubleValue();
021:
022: // We want "-0.0" to convert to -0.0, but the spec as of 1.1
023: // requires Double.valueOf to convert it to 0.0, because the
024: // method is defined to be equivalent to first computing the exact
025: // rational value and then converting to floating-point, and the
026: // exact rational value represented by either string "0.0" or
027: // "-0.0" is 0.
028:
029: // This is apparently a bug in the spec, which I've reported
030: // to sun. As of 1.1, the sun implementation returns -0.0,
031: // but the linux port returns 0.0.
032:
033: // To be safe, we check for this case.
034: if (value == 0.0 && s.charAt(0) == '-')
035: value = -0.0;
036: }
037:
038: public static DFloNum make(double value) {
039: return new DFloNum(value);
040: }
041:
042: public final double doubleValue() {
043: return value;
044: }
045:
046: public long longValue() {
047: return (long) value;
048: }
049:
050: public int hashCode() {
051: return (int) value;
052: }
053:
054: public boolean equals(Object obj) {
055: // take from java.lang.Double.equals:
056: return (obj != null)
057: && (obj instanceof DFloNum)
058: && (Double.doubleToLongBits(((DFloNum) obj).value) == Double
059: .doubleToLongBits(value));
060: }
061:
062: public Numeric add(Object y, int k) {
063: if (y instanceof RealNum)
064: return new DFloNum(value + k * ((RealNum) y).doubleValue());
065: if (!(y instanceof Numeric))
066: throw new IllegalArgumentException();
067: return ((Numeric) y).addReversed(this , k);
068: }
069:
070: public Numeric addReversed(Numeric x, int k) {
071: if (x instanceof RealNum)
072: return new DFloNum(((RealNum) x).doubleValue() + k * value);
073: throw new IllegalArgumentException();
074: }
075:
076: public Numeric mul(Object y) {
077: if (y instanceof RealNum)
078: return new DFloNum(value * ((RealNum) y).doubleValue());
079: if (!(y instanceof Numeric))
080: throw new IllegalArgumentException();
081: return ((Numeric) y).mulReversed(this );
082: }
083:
084: public Numeric mulReversed(Numeric x) {
085: if (x instanceof RealNum)
086: return new DFloNum(((RealNum) x).doubleValue() * value);
087: throw new IllegalArgumentException();
088: }
089:
090: private static final DFloNum one = new DFloNum(1.0);
091:
092: public static final DFloNum one() {
093: return one;
094: }
095:
096: public Numeric div(Object y) {
097: if (y instanceof RealNum)
098: return new DFloNum(value / ((RealNum) y).doubleValue());
099: if (!(y instanceof Numeric))
100: throw new IllegalArgumentException();
101: return ((Numeric) y).divReversed(this );
102: }
103:
104: public Numeric divReversed(Numeric x) {
105: if (x instanceof RealNum)
106: return new DFloNum(((RealNum) x).doubleValue() / value);
107: throw new IllegalArgumentException();
108: }
109:
110: public Numeric power(IntNum y) {
111: return new DFloNum(Math.pow(doubleValue(), y.doubleValue()));
112: }
113:
114: public boolean isNegative() {
115: return value < 0;
116: }
117:
118: public Numeric neg() {
119: return new DFloNum(-value);
120: }
121:
122: public int sign() {
123: return value > 0.0 ? 1 : value < 0.0 ? -1 : value == 0.0 ? 0
124: : -2;
125: }
126:
127: public static int compare(double x, double y) {
128: return x > y ? 1 : x < y ? -1 : x == y ? 0 : -2;
129: }
130:
131: /** Compare (x_num/x_den) with toExact(y). */
132: public static int compare(IntNum x_num, IntNum x_den, double y) {
133: if (Double.isNaN(y))
134: return -2;
135: if (Double.isInfinite(y)) {
136: int result = y >= 0.0 ? -1 : 1;
137: if (!x_den.isZero())
138: return result; // x is finite
139: if (x_num.isZero())
140: return -2; // indeterminate x
141: result >>= 1;
142: return x_num.isNegative() ? result : ~result;
143: } else {
144: long bits = Double.doubleToLongBits(y);
145: boolean neg = bits < 0;
146: int exp = (int) (bits >> 52) & 0x7FF;
147: bits &= 0xfffffffffffffL;
148: if (exp == 0)
149: bits <<= 1;
150: else
151: bits |= 0x10000000000000L;
152: IntNum y_num = IntNum.make(neg ? -bits : bits);
153: if (exp >= 1075)
154: y_num = IntNum.shift(y_num, exp - 1075);
155: else
156: x_num = IntNum.shift(x_num, 1075 - exp);
157: return IntNum.compare(x_num, IntNum.times(y_num, x_den));
158: }
159: }
160:
161: public int compare(Object obj) {
162: if (obj instanceof RatNum) {
163: RatNum y_rat = (RatNum) obj;
164: int i = compare(y_rat.numerator(), y_rat.denominator(),
165: value);
166: return i < -1 ? i : -i;
167: }
168: return compare(value, ((RealNum) obj).doubleValue());
169: }
170:
171: public int compareReversed(Numeric x) {
172: if (x instanceof RatNum) {
173: RatNum x_rat = (RatNum) x;
174: return compare(x_rat.numerator(), x_rat.denominator(),
175: value);
176: }
177: return compare(((RealNum) x).doubleValue(), value);
178: }
179:
180: public boolean isExact() {
181: return false;
182: }
183:
184: public boolean isZero() {
185: return value == 0.0;
186: }
187:
188: /** Converts to the closest exact rational value. */
189: public static RatNum toExact(double value) {
190: if (Double.isInfinite(value))
191: return RatNum.infinity(value >= 0.0 ? 1 : -1);
192: if (Double.isNaN(value))
193: throw new ArithmeticException(
194: "cannot convert NaN to exact rational");
195: long bits = Double.doubleToLongBits(value);
196: boolean neg = bits < 0;
197: int exp = (int) (bits >> 52) & 0x7FF;
198: bits &= 0xfffffffffffffL;
199: if (exp == 0)
200: bits <<= 1;
201: else
202: bits |= 0x10000000000000L;
203: IntNum mant = IntNum.make(neg ? -bits : bits);
204: if (exp >= 1075)
205: return IntNum.shift(mant, exp - 1075);
206: else
207: return RatNum.make(mant, IntNum.shift(IntNum.one(),
208: 1075 - exp));
209: }
210:
211: public String toString() {
212: return (value == 1.0 / 0.0 ? "#i1/0"
213: : value == -1.0 / 0.0 ? "#i-1/0"
214: : Double.isNaN(value) ? "#i0/0" : Double
215: .toString(value));
216: }
217:
218: public String toString(int radix) {
219: if (radix == 10)
220: return toString();
221: return "#d" + toString();
222: }
223:
224: /**
225: * @serialData Writes the number as a double (using writeDouble).
226: */
227: public void writeExternal(ObjectOutput out) throws IOException {
228: out.writeDouble(value);
229: }
230:
231: public void readExternal(ObjectInput in) throws IOException,
232: ClassNotFoundException {
233: value = in.readDouble();
234: }
235:
236: /*
237: static final int mine_e = -1024;
238: static final long bp_1 = 1L << 52;
239:
240: static ?? flonum_digits (foubel v, long f, int e)
241: {
242: boolean round_p = (f & 1) == 0;
243: if (e >= 0)
244: {
245: IntNum be = 1L << e; // ???
246: if (f != bp_1)
247: return scale (f * be * 2 (?), 2, be, be, 0, round_p, round_p, v);
248: else
249: return scale (f * be * 4 (?), 4, 2 * be, b2, 0, round_p, round_p, v);
250: }
251: else
252: {
253: if (e == min_e || f != bp_1)
254: return scale (f * 2 (?), 2 ** (1 - 3), 1, 1, 0, round_p, round_p, v);
255: else
256: return scale (f * 4 (?), 2 ** (2 - e), 2, 1, 0, round_p, round_p, v);
257: }
258: }
259:
260: static ?? scale (IntNum r, IntNum s, IntNum m_plus, IntNum m_minus,
261: int k, boolean low_ok?, boolean high_ok, double v)
262: {
263: int est = (int) Math.ceil(log10(v) - 1e-10);
264: if (est >= 0)
265: return fixup(r, s * expt10(est), m_plus, m_minus, est, low_ok, high_ok);
266: else
267: {
268: IntNum scale = expt10(-ext);
269: return fixup(r * scale, s, scale * m_plus, scale * m_minus,
270: est, low_ok, high_ok);
271: }
272: }
273:
274: static ?? fixup (IntNum r, IntNum s, IntNum m_plus, IntNum m_minus,
275: int k, boolean low_ok, boolean high_ok)
276: {
277: ...;
278: }
279:
280: static ?? generate (IntNum r, IntNum s, IntNum m_plus, IntNum m_minus,
281: boolean low_ok, boolean high_ok)
282: {
283: IntNum d = new IntNum(), r = new IntNum();
284: IntNum.divide (r, s, d, r, mode?);
285: d = d.canonicalize();
286: r = r.canonicalize();
287: boolean tc1 = ?;
288: boolean tc2 = ?;
289: }
290:
291: static IntNum expt10 = null;
292:
293: static IntNum expt10 (int k)
294: {
295: if (expt10 == null)
296: {
297: expt10 = new IntNum[326];
298: int i = 0;
299: IntNum v = IntNum.one();
300: for (; ; i++)
301: {
302: expt10[i] = v;
303: if (i == 325)
304: break;
305: v = IntNum.times(v, 10);
306: }
307: }
308: return expt10[k];
309: }
310:
311: static double InvLog10 = 1.0 / Math.log(10);
312:
313: static double log10 (double x) { return Math.log(x) * InvLog10; }
314: */
315: }
|