001: /*
002: * Complex.java
003: *
004: * Copyright (C) 2003 Peter Graves
005: * $Id: Complex.java,v 1.6 2003/11/15 11:03:34 beedlem Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.lisp;
023:
024: public final class Complex extends LispObject {
025: private final LispObject realpart;
026: private final LispObject imagpart;
027:
028: private Complex(LispObject realpart, LispObject imagpart) {
029: this .realpart = realpart;
030: this .imagpart = imagpart;
031: }
032:
033: public static LispObject getInstance(LispObject realpart,
034: LispObject imagpart) throws ConditionThrowable {
035: if (!realpart.realp())
036: throw new ConditionThrowable(new TypeError(realpart,
037: "real number"));
038: if (!imagpart.realp())
039: throw new ConditionThrowable(new TypeError(imagpart,
040: "real number"));
041: if (realpart instanceof LispFloat)
042: imagpart = LispFloat.coerceToFloat(imagpart);
043: else if (imagpart instanceof LispFloat)
044: realpart = LispFloat.coerceToFloat(realpart);
045: if (imagpart instanceof Fixnum) {
046: if (((Fixnum) imagpart).getValue() == 0)
047: return realpart;
048: }
049: return new Complex(realpart, imagpart);
050: }
051:
052: public LispObject getRealPart() {
053: return realpart;
054: }
055:
056: public LispObject getImaginaryPart() {
057: return imagpart;
058: }
059:
060: public LispObject typeOf() {
061: return Symbol.COMPLEX;
062: }
063:
064: public LispClass classOf() {
065: return BuiltInClass.COMPLEX;
066: }
067:
068: public LispObject typep(LispObject type) throws ConditionThrowable {
069: if (type == Symbol.COMPLEX)
070: return T;
071: if (type == Symbol.NUMBER)
072: return T;
073: if (type == BuiltInClass.COMPLEX)
074: return T;
075: if (type == BuiltInClass.NUMBER)
076: return T;
077: return super .typep(type);
078: }
079:
080: public LispObject NUMBERP() {
081: return T;
082: }
083:
084: public boolean numberp() {
085: return true;
086: }
087:
088: public boolean eql(LispObject obj) {
089: if (this == obj)
090: return true;
091: if (obj instanceof Complex) {
092: Complex c = (Complex) obj;
093: return realpart.eql(c.realpart) && imagpart.eql(c.imagpart);
094: }
095: return false;
096: }
097:
098: public boolean equal(LispObject obj) {
099: return eql(obj);
100: }
101:
102: public boolean equalp(LispObject obj) throws ConditionThrowable {
103: return isEqualTo(obj);
104: }
105:
106: public final LispObject incr() throws ConditionThrowable {
107: return new Complex(realpart.add(Fixnum.ONE), imagpart);
108: }
109:
110: public final LispObject decr() throws ConditionThrowable {
111: return new Complex(realpart.subtract(Fixnum.ONE), imagpart);
112: }
113:
114: public LispObject add(LispObject obj) throws ConditionThrowable {
115: if (obj instanceof Complex) {
116: Complex c = (Complex) obj;
117: return getInstance(realpart.add(c.realpart), imagpart
118: .add(c.imagpart));
119: }
120: return getInstance(realpart.add(obj), imagpart);
121: }
122:
123: public LispObject subtract(LispObject obj)
124: throws ConditionThrowable {
125: if (obj instanceof Complex) {
126: Complex c = (Complex) obj;
127: return getInstance(realpart.subtract(c.realpart), imagpart
128: .subtract(c.imagpart));
129: }
130: return getInstance(realpart.subtract(obj), imagpart);
131: }
132:
133: public LispObject multiplyBy(LispObject obj)
134: throws ConditionThrowable {
135: if (obj instanceof Complex) {
136: LispObject a = realpart;
137: LispObject b = imagpart;
138: LispObject c = ((Complex) obj).getRealPart();
139: LispObject d = ((Complex) obj).getImaginaryPart();
140: // xy = (ac - bd) + i(ad + bc)
141: // real part = ac - bd
142: // imag part = (a + b)(c + d) - ac - bd
143: LispObject ac = a.multiplyBy(c);
144: LispObject bd = b.multiplyBy(d);
145: return Complex.getInstance(ac.subtract(bd), a.add(b)
146: .multiplyBy(c.add(d)).subtract(ac).subtract(bd));
147: }
148: return Complex.getInstance(realpart.multiplyBy(obj), imagpart
149: .multiplyBy(obj));
150: }
151:
152: public LispObject divideBy(LispObject obj)
153: throws ConditionThrowable {
154: if (obj instanceof Complex) {
155: LispObject a = realpart;
156: LispObject b = imagpart;
157: LispObject c = ((Complex) obj).getRealPart();
158: LispObject d = ((Complex) obj).getImaginaryPart();
159: LispObject ac = a.multiplyBy(c);
160: LispObject bd = b.multiplyBy(d);
161: LispObject bc = b.multiplyBy(c);
162: LispObject ad = a.multiplyBy(d);
163: LispObject denominator = c.multiplyBy(c).add(
164: d.multiplyBy(d));
165: return Complex.getInstance(
166: ac.add(bd).divideBy(denominator), bc.subtract(ad)
167: .divideBy(denominator));
168: }
169: return Complex.getInstance(realpart.divideBy(obj), imagpart
170: .divideBy(obj));
171: }
172:
173: public boolean isEqualTo(LispObject obj) throws ConditionThrowable {
174: if (obj instanceof Complex) {
175: Complex c = (Complex) obj;
176: return (realpart.isEqualTo(c.realpart) && imagpart
177: .isEqualTo(c.imagpart));
178: }
179: if (obj.numberp()) {
180: // obj is a number, but not complex.
181: if (imagpart instanceof LispFloat) {
182: if (((LispFloat) imagpart).getValue() == 0) {
183: if (obj instanceof Fixnum)
184: return ((Fixnum) obj).getValue() == ((LispFloat) realpart)
185: .getValue();
186: if (obj instanceof LispFloat)
187: return ((LispFloat) obj).getValue() == ((LispFloat) realpart)
188: .getValue();
189: }
190: }
191: return false;
192: }
193: throw new ConditionThrowable(new TypeError(obj, "number"));
194: }
195:
196: public boolean isNotEqualTo(LispObject obj)
197: throws ConditionThrowable {
198: return !isEqualTo(obj);
199: }
200:
201: public LispObject ABS() throws ConditionThrowable {
202: double real = LispFloat.coerceToFloat(realpart).getValue();
203: double imag = LispFloat.coerceToFloat(imagpart).getValue();
204: return new LispFloat(Math.sqrt(real * real + imag * imag));
205: }
206:
207: public boolean zerop() throws ConditionThrowable {
208: return realpart.zerop() && imagpart.zerop();
209: }
210:
211: public LispObject COMPLEXP() {
212: return T;
213: }
214:
215: public String toString() {
216: StringBuffer sb = new StringBuffer("#C(");
217: sb.append(String.valueOf(realpart));
218: sb.append(' ');
219: sb.append(String.valueOf(imagpart));
220: sb.append(')');
221: return sb.toString();
222: }
223: }
|