source: branches/0.25.x/abcl/src/org/armedbear/lisp/Complex.java

Last change on this file was 12940, checked in by ehuelsmann, 15 years ago

Fix loss of precision in (expt <non-double> <complex-double>),
fixes last Maxima failure.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.0 KB
Line 
1/*
2 * Complex.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: Complex.java 12940 2010-10-02 21:39:52Z ehuelsmann $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38public final class Complex extends LispObject
39{
40  public final LispObject realpart;
41  public final LispObject imagpart;
42
43  private Complex(LispObject realpart, LispObject imagpart)
44  {
45    this.realpart = realpart;
46    this.imagpart = imagpart;
47  }
48
49  public static LispObject getInstance(LispObject realpart,
50                                       LispObject imagpart)
51
52  {
53    if (!realpart.realp())
54      return type_error(realpart, Symbol.REAL);
55    if (!imagpart.realp())
56      return type_error(imagpart, Symbol.REAL);
57    if (realpart instanceof DoubleFloat)
58      imagpart = DoubleFloat.coerceToFloat(imagpart);
59    else if (imagpart instanceof DoubleFloat)
60      realpart = DoubleFloat.coerceToFloat(realpart);
61    else if (realpart instanceof SingleFloat)
62      imagpart = SingleFloat.coerceToFloat(imagpart);
63    else if (imagpart instanceof SingleFloat)
64      realpart = SingleFloat.coerceToFloat(realpart);
65    if (imagpart instanceof Fixnum)
66      {
67        if (((Fixnum)imagpart).value == 0)
68          return realpart;
69      }
70    return new Complex(realpart, imagpart);
71  }
72
73  public LispObject getRealPart()
74  {
75    return realpart;
76  }
77
78  public LispObject getImaginaryPart()
79  {
80    return imagpart;
81  }
82
83  /** Coerces the complex parts into DoubleFloats
84   *
85   * @return a new complex with double-float real and imaginary parts
86   */
87  public LispObject coerceToDoubleFloat() {
88      return getInstance(DoubleFloat.coerceToFloat(realpart),
89                         DoubleFloat.coerceToFloat(imagpart));
90  }
91
92  @Override
93  public LispObject typeOf()
94  {
95    return Symbol.COMPLEX;
96  }
97
98  @Override
99  public LispObject classOf()
100  {
101    return BuiltInClass.COMPLEX;
102  }
103
104  @Override
105  public LispObject typep(LispObject type)
106  {
107    if (type == Symbol.COMPLEX)
108      return T;
109    if (type == Symbol.NUMBER)
110      return T;
111    if (type == BuiltInClass.COMPLEX)
112      return T;
113    if (type == BuiltInClass.NUMBER)
114      return T;
115    return super.typep(type);
116  }
117
118  @Override
119  public boolean numberp()
120  {
121    return true;
122  }
123
124  @Override
125  public boolean eql(LispObject obj)
126  {
127    if (this == obj)
128      return true;
129    if (obj instanceof Complex)
130      {
131        Complex c = (Complex) obj;
132        return realpart.eql(c.realpart) && imagpart.eql(c.imagpart);
133      }
134    return false;
135  }
136
137  @Override
138  public boolean equal(LispObject obj)
139  {
140    return eql(obj);
141  }
142
143  @Override
144  public boolean equalp(LispObject obj)
145  {
146    if (this == obj)
147      return true;
148    if (obj instanceof Complex)
149      {
150        Complex c = (Complex) obj;
151        return (realpart.isEqualTo(c.realpart) &&
152                imagpart.isEqualTo(c.imagpart));
153      }
154    if (obj.numberp())
155      {
156        // obj is a number, but not complex.
157        if (imagpart instanceof SingleFloat)
158          {
159            if (((SingleFloat)imagpart).value == 0)
160              {
161                if (obj instanceof Fixnum)
162                  return ((Fixnum)obj).value == ((SingleFloat)realpart).value;
163                if (obj instanceof SingleFloat)
164                  return ((SingleFloat)obj).value == ((SingleFloat)realpart).value;
165              }
166          }
167        if (imagpart instanceof DoubleFloat)
168          {
169            if (((DoubleFloat)imagpart).value == 0)
170              {
171                if (obj instanceof Fixnum)
172                  return ((Fixnum)obj).value == ((DoubleFloat)realpart).value;
173                if (obj instanceof DoubleFloat)
174                  return ((DoubleFloat)obj).value == ((DoubleFloat)realpart).value;
175              }
176          }
177      }
178    return false;
179  }
180
181  @Override
182  public final LispObject incr()
183  {
184    return new Complex(realpart.add(Fixnum.ONE), imagpart);
185  }
186
187  @Override
188  public final LispObject decr()
189  {
190    return new Complex(realpart.subtract(Fixnum.ONE), imagpart);
191  }
192
193  @Override
194  public LispObject add(LispObject obj)
195  {
196    if (obj instanceof Complex)
197      {
198        Complex c = (Complex) obj;
199        return getInstance(realpart.add(c.realpart), imagpart.add(c.imagpart));
200      }
201    return getInstance(realpart.add(obj), imagpart);
202  }
203
204  @Override
205  public LispObject subtract(LispObject obj)
206  {
207    if (obj instanceof Complex)
208      {
209        Complex c = (Complex) obj;
210        return getInstance(realpart.subtract(c.realpart),
211                           imagpart.subtract(c.imagpart));
212      }
213    return getInstance(realpart.subtract(obj), imagpart);
214  }
215
216  @Override
217  public LispObject multiplyBy(LispObject obj)
218  {
219    if (obj instanceof Complex)
220      {
221        LispObject a = realpart;
222        LispObject b = imagpart;
223        LispObject c = ((Complex)obj).getRealPart();
224        LispObject d = ((Complex)obj).getImaginaryPart();
225        // xy = (ac - bd) + i(ad + bc)
226        // real part = ac - bd
227        // imag part = ad + bc
228        LispObject ac = a.multiplyBy(c);
229        LispObject bd = b.multiplyBy(d);
230        LispObject ad = a.multiplyBy(d);
231        LispObject bc = b.multiplyBy(c);
232        return Complex.getInstance(ac.subtract(bd), ad.add(bc));
233      }
234    return Complex.getInstance(realpart.multiplyBy(obj),
235                               imagpart.multiplyBy(obj));
236  }
237
238  @Override
239  public LispObject divideBy(LispObject obj)
240  {
241    if (obj instanceof Complex)
242      {
243        LispObject a = realpart;
244        LispObject b = imagpart;
245        LispObject c = ((Complex)obj).getRealPart();
246        LispObject d = ((Complex)obj).getImaginaryPart();
247        LispObject ac = a.multiplyBy(c);
248        LispObject bd = b.multiplyBy(d);
249        LispObject bc = b.multiplyBy(c);
250        LispObject ad = a.multiplyBy(d);
251        LispObject denominator = c.multiplyBy(c).add(d.multiplyBy(d));
252        return Complex.getInstance(ac.add(bd).divideBy(denominator),
253                                   bc.subtract(ad).divideBy(denominator));
254      }
255    return Complex.getInstance(realpart.divideBy(obj),
256                               imagpart.divideBy(obj));
257  }
258
259  @Override
260  public boolean isEqualTo(LispObject obj)
261  {
262    if (obj instanceof Complex)
263      {
264        Complex c = (Complex) obj;
265        return (realpart.isEqualTo(c.realpart) &&
266                imagpart.isEqualTo(c.imagpart));
267      }
268    if (obj.numberp())
269      {
270        // obj is a number, but not complex.
271        if (imagpart instanceof SingleFloat)
272          {
273            if (((SingleFloat)imagpart).value == 0)
274              {
275                if (obj instanceof Fixnum)
276                  return ((Fixnum)obj).value == ((SingleFloat)realpart).value;
277                if (obj instanceof SingleFloat)
278                  return ((SingleFloat)obj).value == ((SingleFloat)realpart).value;
279                if (obj instanceof DoubleFloat)
280                  return ((DoubleFloat)obj).value == ((SingleFloat)realpart).value;
281              }
282          }
283        if (imagpart instanceof DoubleFloat)
284          {
285            if (((DoubleFloat)imagpart).value == 0)
286              {
287                if (obj instanceof Fixnum)
288                  return ((Fixnum)obj).value == ((DoubleFloat)realpart).value;
289                if (obj instanceof SingleFloat)
290                  return ((SingleFloat)obj).value == ((DoubleFloat)realpart).value;
291                if (obj instanceof DoubleFloat)
292                  return ((DoubleFloat)obj).value == ((DoubleFloat)realpart).value;
293              }
294          }
295        return false;
296      }
297    type_error(obj, Symbol.NUMBER);
298    // Not reached.
299    return false;
300  }
301
302  @Override
303  public boolean isNotEqualTo(LispObject obj)
304  {
305    return !isEqualTo(obj);
306  }
307
308  @Override
309  public LispObject ABS()
310  {
311    if (realpart.zerop())
312      return imagpart.ABS();
313    double real = DoubleFloat.coerceToFloat(realpart).value;
314    double imag = DoubleFloat.coerceToFloat(imagpart).value;
315    if (realpart instanceof DoubleFloat)
316      return new DoubleFloat(Math.hypot(real, imag));
317    else
318      return new SingleFloat((float)Math.hypot(real, imag));
319  }
320
321  @Override
322  public boolean zerop()
323  {
324    return realpart.zerop() && imagpart.zerop();
325  }
326
327  @Override
328  public LispObject COMPLEXP()
329  {
330    return T;
331  }
332
333  @Override
334  public int sxhash()
335  {
336    return (mix(realpart.sxhash(), imagpart.sxhash()) & 0x7fffffff);
337  }
338
339  @Override
340  public int psxhash()
341  {
342    return (mix(realpart.psxhash(), imagpart.psxhash()) & 0x7fffffff);
343  }
344
345  @Override
346  public String writeToString()
347  {
348    StringBuilder sb = new StringBuilder("#C(");
349    sb.append(realpart.writeToString());
350    sb.append(' ');
351    sb.append(imagpart.writeToString());
352    sb.append(')');
353    return sb.toString();
354  }
355}
Note: See TracBrowser for help on using the repository browser.