1 // Copyright (c) 1997, 2004, 2006  Per M.A. Bothner.
2 // This is free software;  for terms and warranty disclaimer see ./COPYING.
3 
4 package gnu.math;
5 import java.math.BigDecimal;
6 
7 public abstract class RealNum extends Complex
8   /* #ifdef JAVA2 */
9   implements Comparable
10   /* #endif */
11 {
re()12   public final RealNum re() { return this; }
im()13   public final RealNum im() { return IntNum.zero(); }
14 
angle()15   public final RealNum angle() {
16     return isNegative() ? DFloNum.valueOf(Math.PI) : DFloNum.zero();
17   }
18 
vectorPart()19     @Override public final Quaternion vectorPart() { return IntNum.zero(); }
unitVector()20     @Override public final Quaternion unitVector() { return IntNum.zero(); }
unitQuaternion()21     @Override public final Quaternion unitQuaternion() {
22         switch (sign()) {
23             case  1: return IntNum.one();
24             case  0: return IntNum.zero();
25             case -1: return IntNum.minusOne();
26             case -2: default: return this;     // NaN
27         }
28     }
conjugate()29     @Override public final Quaternion conjugate() { return this; }
30 
isReal(Object value)31     public static boolean isReal(Object value) {
32         return (value instanceof Number
33                 && (value instanceof RealNum || ! (value instanceof Numeric)));
34     }
35 
asRealNumOrNull(Object value)36   public static RealNum asRealNumOrNull (Object value)
37   {
38     if (value instanceof RealNum)
39       return (RealNum) value;
40     if (value instanceof Float || value instanceof Double)
41       return new DFloNum(((Number) value).doubleValue());
42     return RatNum.asRatNumOrNull(value);
43   }
44 
isNegative()45   public abstract boolean isNegative ();
46 
47     @Override
classifyFinite()48     public int classifyFinite() {
49         double d = doubleValue();
50         return Double.isNaN(d) ? -1 : Double.isInfinite(d) ? 0 : 1;
51     }
52 
53   /** Return 1 if {@code >0}; 0 if {@code ==0}; -1 if {@code <0}; -2 if {@code NaN}. */
sign()54   public abstract int sign ();
55 
max(RealNum x)56   public RealNum max (RealNum x)
57   {
58     boolean exact = isExact () && x.isExact ();
59     RealNum result = grt (x) ? this : x;
60     if (!exact && result.isExact ())
61       result = new DFloNum (result.doubleValue ());
62     return result;
63   }
64 
min(RealNum x)65   public RealNum min (RealNum x)
66   {
67     boolean exact = isExact () && x.isExact ();
68     RealNum result = grt (x) ? x : this;
69     if (!exact && result.isExact ())
70       result = new DFloNum (result.doubleValue ());
71     return result;
72   }
73 
add(RealNum x, RealNum y, int k)74   public static RealNum add (RealNum x, RealNum y, int k)
75   {
76     return (RealNum)(x.add(y, k));
77   }
78 
times(RealNum x, RealNum y)79   public static RealNum times(RealNum x, RealNum y)
80   {
81     return (RealNum)(x.mul(y));
82   }
83 
divide(RealNum x, RealNum y)84   public static RealNum divide (RealNum x, RealNum y)
85   {
86     return (RealNum)(x.div(y));
87   }
88 
89   /* These are defined in Complex, but have to be overridden. */
add(Object obj, int k)90   public abstract Numeric add (Object obj, int k);
mul(Object obj)91   public abstract Numeric mul (Object obj);
div(Object obj)92   public abstract Numeric div (Object obj);
93 
abs()94   public Numeric abs ()
95   {
96     return isNegative () ? neg () : this;
97   }
98 
rneg()99   public RealNum rneg() { return (RealNum) neg(); }
100 
isZero()101   public boolean isZero ()
102   {
103     return sign () == 0;
104   }
105 
106   /** Convert to an exact number.
107    * Implements the Scheme {@code inexact->exact} (for real numbers).
108    */
toExact()109   public RatNum toExact ()
110   {
111     return DFloNum.toExact(doubleValue ());
112   }
113 
toInexact()114   public RealNum toInexact ()
115   {
116     if (isExact())
117       return new DFloNum(doubleValue());
118     else
119       return this;
120   }
121 
122   /** Converts a real to an integer, according to a specified rounding mode.
123    * Note an inexact argument gives an inexact result, following Scheme.
124    * See also RatNum.toExactInt. */
toInt(double d, int rounding_mode)125   public static double toInt (double d, int rounding_mode)
126   {
127     switch (rounding_mode)
128       {
129       case FLOOR:
130 	return Math.floor(d);
131       case CEILING:
132 	return Math.ceil(d);
133       case TRUNCATE:
134 	return d < 0.0 ? Math.ceil (d) : Math.floor (d);
135       case ROUND:
136 	return Math.rint(d);
137       default:  // Illegal rounding_mode
138 	return d;
139       }
140   }
141 
142   /** Converts a real to an integer, according to a specified rounding mode.
143    * Note an inexact argument gives an inexact result, following Scheme.
144    * See also toExactInt. */
toInt(int rounding_mode)145   public RealNum toInt (int rounding_mode)
146   {
147     return new DFloNum(toInt(doubleValue(), rounding_mode));
148   }
149 
150   /** Converts to an exact integer, with specified rounding mode. */
toExactInt(int rounding_mode)151   public IntNum toExactInt (int rounding_mode)
152   {
153     return toExactInt(doubleValue(), rounding_mode);
154   }
155 
156   /** Converts real to an exact integer, with specified rounding mode. */
toExactInt(double value, int rounding_mode)157   public static IntNum toExactInt (double value, int rounding_mode)
158   {
159     return toExactInt(toInt(value, rounding_mode));
160   }
161 
162   /** Converts an integral double (such as a toInt result) to an IntNum. */
toExactInt(double value)163   public static IntNum toExactInt (double value)
164   {
165     if (Double.isInfinite (value) || Double.isNaN (value))
166       throw new ArithmeticException ("cannot convert "+value+" to exact integer");
167     long bits = Double.doubleToLongBits (value);
168     boolean neg = bits < 0;
169     int exp = (int) (bits >> 52) & 0x7FF;
170     bits &= 0xfffffffffffffL;
171     if (exp == 0)
172       bits <<= 1;
173     else
174       bits |= 0x10000000000000L;
175     if (exp <= 1075)
176       {
177 	int rshift = 1075 - exp;
178 	if (rshift > 53)
179 	  return IntNum.zero();
180 	bits >>= rshift;
181 	return IntNum.make (neg ? -bits : bits);
182       }
183     return IntNum.shift (IntNum.make (neg ? -bits : bits), exp - 1075);
184   }
185 
exp()186   public Complex exp ()
187   {
188     return new DFloNum(Math.exp(doubleValue()));
189   }
190 
log()191   public Complex log ()
192   {
193     double x = doubleValue();
194     if (x <= 0)
195       return DComplex.log(x, 0.0);
196     return new DFloNum(Math.log(x));
197   }
198 
sin()199     @Override public final RealNum sin() {
200         return new DFloNum(Math.sin(doubleValue()));
201     }
cos()202     @Override public final RealNum cos() {
203         return new DFloNum(Math.cos(doubleValue()));
204     }
tan()205     @Override public final RealNum tan() {
206         return new DFloNum(Math.tan(doubleValue()));
207     }
208 
sqrt()209   public final Complex sqrt ()
210   {
211     double d = doubleValue();
212     if (d >= 0)
213       return new DFloNum(Math.sqrt(d));
214     else
215       return Complex.make(IntNum.zero(), new DFloNum(Math.sqrt(-d)));
216   }
217 
218   /** Convert double to (rounded) integer, after multiplying by 10**k. */
toScaledInt(double f, int k)219   public static IntNum toScaledInt (double f, int k)
220   {
221     return toScaledInt(DFloNum.toExact(f), k);
222   }
223 
224   /** Convert rational to (rounded) integer, after multiplying by 10**k. */
toScaledInt(RatNum r, int k)225   public static IntNum toScaledInt (RatNum r, int k)
226   {
227     if (k != 0)
228       {
229 	IntNum power = IntNum.power(IntNum.ten(), k < 0 ? -k : k);
230 	IntNum num = r.numerator();
231 	IntNum den = r.denominator();
232 	if (k >= 0)
233 	  num = IntNum.times(num, power);
234 	else
235 	  den = IntNum.times(den, power);
236 	r = RatNum.make(num, den);
237       }
238     return r.toExactInt(ROUND);
239   }
240 
241   /** Convert this to (rounded) integer, after multiplying by 10**k. */
toScaledInt(int k)242   public IntNum toScaledInt (int k)
243   {
244     return toScaledInt(toExact(), k);
245   }
246 
247   /*
248   public static String toScaledIntString (double f, int k)
249   {
250     switch (k)
251       {
252       case 0:  break;
253       case 1:  f = f * 10;  break;
254       case 2:  f = f * 100;  break;
255       case 3:  f = f * 1000;  break;
256       default: return toScaledInt(f, k).toString();
257       }
258     return Long.toString((long) f);
259   }
260   */
261 
262   /** Implements the Comparable interface.
263    * This ordering isn't fully consistent with equals, since say
264    * it returns 0 when comparing 1.5 and 3/2, though they are not equals.
265    */
compareTo(Object o)266   public int compareTo(Object o)
267   {
268     return compare(o);
269   }
270 
asBigDecimal()271   public java.math.BigDecimal asBigDecimal ()
272   {
273     return new BigDecimal(doubleValue());
274   }
275 
toStringScientific(float d)276   public static String toStringScientific (float d)
277   {
278     return toStringScientific(Float.toString(d));
279   }
280 
toStringScientific(double d)281   public static String toStringScientific (double d)
282   {
283     return toStringScientific(Double.toString(d));
284   }
285 
286   /** Convert result of Double.toString or Float.toString to
287    * scientific notation.
288    * Does not validate the input.
289    */
toStringScientific(String dstr)290   public static String toStringScientific (String dstr)
291   {
292     int indexE = dstr.indexOf('E');
293     if (indexE >= 0)
294       return dstr;
295     int len = dstr.length();
296     // Check for "Infinity" or "NaN".
297     char ch = dstr.charAt(len-1);
298     if (ch == 'y' || ch == 'N')
299       return dstr;
300     StringBuffer sbuf = new StringBuffer(len+10);
301     int exp = toStringScientific(dstr, sbuf);
302     sbuf.append('E');
303     sbuf.append(exp);
304     return sbuf.toString();
305   }
306 
toStringScientific(String dstr, StringBuffer sbuf)307   public static int toStringScientific (String dstr, StringBuffer sbuf)
308   {
309     boolean neg = dstr.charAt(0) == '-';
310     if (neg)
311       sbuf.append('-');
312     int pos = neg ? 1 : 0;
313     int exp;
314     int len = dstr.length();
315     if (dstr.charAt(pos) == '0')
316       { // Value is < 1.0.
317         int start = pos;
318         for (;;)
319           {
320             if (pos == len)
321               {
322                 sbuf.append("0");
323                 exp = 0;
324                 break;
325               }
326             char ch = dstr.charAt(pos++);
327             if (ch >= '0' && ch <= '9' && (ch != '0' || pos == len))
328               {
329                 sbuf.append(ch);
330                 sbuf.append('.');
331                 exp = ch == '0' ? 0 : start - pos + 2;
332                 if (pos == len)
333                   sbuf.append('0');
334                 else
335                   {
336                     while (pos < len)
337                       sbuf.append(dstr.charAt(pos++));
338                   }
339                 break;
340               }
341           }
342       }
343     else
344       {
345         // Number of significant digits in string.
346         int ndigits = len - (neg ? 2 : 1);
347         int dot = dstr.indexOf('.');
348         // Number of fractional digits is len-dot-1.
349         // We want ndigits-1 fractional digits.  Hence we need to move the
350         // decimal point ndigits-1-(len-dot-1) == ndigits-len+dot positions
351         // to the left. This becomes the exponent we need.
352         exp = ndigits - len + dot;
353         sbuf.append(dstr.charAt(pos++)); // Copy initial digit before point.
354         sbuf.append('.');
355         while (pos < len)
356           {
357             char ch = dstr.charAt(pos++);
358             if (ch != '.')
359               sbuf.append(ch);
360           }
361       }
362     // Remove excess zeros.
363     pos = sbuf.length();
364     int slen = -1;
365     for (;;)
366       {
367         char ch = sbuf.charAt(--pos);
368         if (ch == '0')
369           slen = pos;
370         else
371           {
372             if (ch == '.')
373               slen = pos + 2;
374             break;
375           }
376       }
377     if (slen >= 0)
378       sbuf.setLength(slen);
379     return exp;
380   }
381 
toStringDecimal(String dstr)382   public static String toStringDecimal (String dstr)
383   {
384     int indexE = dstr.indexOf('E');
385     if (indexE < 0)
386       return dstr;
387     int len = dstr.length();
388     // Check for "Infinity" or "NaN".
389     char ch = dstr.charAt(len-1);
390     if (ch == 'y' || ch == 'N')
391       return dstr;
392     StringBuffer sbuf = new StringBuffer(len+10);
393     boolean neg = dstr.charAt(0) == '-';
394     if (dstr.charAt(indexE+1) != '-')
395       {
396         throw new UnsupportedOperationException("not implemented: toStringDecimal given non-negative exponent: "+dstr);
397       }
398     else
399       {
400         int pos = indexE+2;  // skip "E-".
401         int exp = 0;
402         while (pos < len)
403           exp = 10 * exp + (dstr.charAt(pos++) - '0');
404         if (neg)
405           sbuf.append('-');
406         sbuf.append("0.");
407         while (--exp > 0) sbuf.append('0');
408         for (pos = 0; (ch = dstr.charAt(pos++)) != 'E'; )
409           {
410             if (ch != '-' & ch != '.'
411                 && (ch != '0' || pos < indexE))
412               sbuf.append(ch);
413           }
414         return sbuf.toString();
415       }
416   }
417 }
418