001: /*
002: * Complex.java
003: *
004: * Copyright (C) 2003-2004 Peter Graves
005: * $Id: Complex.java,v 1.29 2004/06/04 16:24:29 piso 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: return signal(new TypeError(realpart, Symbol.REAL));
037: if (!imagpart.realp())
038: return signal(new TypeError(imagpart, Symbol.REAL));
039: if (realpart instanceof LispFloat)
040: imagpart = LispFloat.coerceToFloat(imagpart);
041: else if (imagpart instanceof LispFloat)
042: realpart = LispFloat.coerceToFloat(realpart);
043: if (imagpart instanceof Fixnum) {
044: if (((Fixnum) imagpart).getValue() == 0)
045: return realpart;
046: }
047: return new Complex(realpart, imagpart);
048: }
049:
050: public LispObject getRealPart() {
051: return realpart;
052: }
053:
054: public LispObject getImaginaryPart() {
055: return imagpart;
056: }
057:
058: public LispObject typeOf() {
059: return Symbol.COMPLEX;
060: }
061:
062: public LispClass classOf() {
063: return BuiltInClass.COMPLEX;
064: }
065:
066: public LispObject typep(LispObject type) throws ConditionThrowable {
067: if (type == Symbol.COMPLEX)
068: return T;
069: if (type == Symbol.NUMBER)
070: return T;
071: if (type == BuiltInClass.COMPLEX)
072: return T;
073: if (type == BuiltInClass.NUMBER)
074: return T;
075: return super .typep(type);
076: }
077:
078: public LispObject NUMBERP() {
079: return T;
080: }
081:
082: public boolean numberp() {
083: return true;
084: }
085:
086: public boolean eql(LispObject obj) {
087: if (this == obj)
088: return true;
089: if (obj instanceof Complex) {
090: Complex c = (Complex) obj;
091: return realpart.eql(c.realpart) && imagpart.eql(c.imagpart);
092: }
093: return false;
094: }
095:
096: public boolean equal(LispObject obj) {
097: return eql(obj);
098: }
099:
100: public boolean equalp(LispObject obj) throws ConditionThrowable {
101: return isEqualTo(obj);
102: }
103:
104: public final LispObject incr() throws ConditionThrowable {
105: return new Complex(realpart.add(Fixnum.ONE), imagpart);
106: }
107:
108: public final LispObject decr() throws ConditionThrowable {
109: return new Complex(realpart.subtract(Fixnum.ONE), imagpart);
110: }
111:
112: public LispObject add(LispObject obj) throws ConditionThrowable {
113: if (obj instanceof Complex) {
114: Complex c = (Complex) obj;
115: return getInstance(realpart.add(c.realpart), imagpart
116: .add(c.imagpart));
117: }
118: return getInstance(realpart.add(obj), imagpart);
119: }
120:
121: public LispObject subtract(LispObject obj)
122: throws ConditionThrowable {
123: if (obj instanceof Complex) {
124: Complex c = (Complex) obj;
125: return getInstance(realpart.subtract(c.realpart), imagpart
126: .subtract(c.imagpart));
127: }
128: return getInstance(realpart.subtract(obj), imagpart);
129: }
130:
131: public LispObject multiplyBy(LispObject obj)
132: throws ConditionThrowable {
133: if (obj instanceof Complex) {
134: LispObject a = realpart;
135: LispObject b = imagpart;
136: LispObject c = ((Complex) obj).getRealPart();
137: LispObject d = ((Complex) obj).getImaginaryPart();
138: // xy = (ac - bd) + i(ad + bc)
139: // real part = ac - bd
140: // imag part = (a + b)(c + d) - ac - bd
141: LispObject ac = a.multiplyBy(c);
142: LispObject bd = b.multiplyBy(d);
143: return Complex.getInstance(ac.subtract(bd), a.add(b)
144: .multiplyBy(c.add(d)).subtract(ac).subtract(bd));
145: }
146: return Complex.getInstance(realpart.multiplyBy(obj), imagpart
147: .multiplyBy(obj));
148: }
149:
150: public LispObject divideBy(LispObject obj)
151: throws ConditionThrowable {
152: if (obj instanceof Complex) {
153: LispObject a = realpart;
154: LispObject b = imagpart;
155: LispObject c = ((Complex) obj).getRealPart();
156: LispObject d = ((Complex) obj).getImaginaryPart();
157: LispObject ac = a.multiplyBy(c);
158: LispObject bd = b.multiplyBy(d);
159: LispObject bc = b.multiplyBy(c);
160: LispObject ad = a.multiplyBy(d);
161: LispObject denominator = c.multiplyBy(c).add(
162: d.multiplyBy(d));
163: return Complex.getInstance(
164: ac.add(bd).divideBy(denominator), bc.subtract(ad)
165: .divideBy(denominator));
166: }
167: return Complex.getInstance(realpart.divideBy(obj), imagpart
168: .divideBy(obj));
169: }
170:
171: public boolean isEqualTo(LispObject obj) throws ConditionThrowable {
172: if (obj instanceof Complex) {
173: Complex c = (Complex) obj;
174: return (realpart.isEqualTo(c.realpart) && imagpart
175: .isEqualTo(c.imagpart));
176: }
177: if (obj.numberp()) {
178: // obj is a number, but not complex.
179: if (imagpart instanceof LispFloat) {
180: if (((LispFloat) imagpart).getValue() == 0) {
181: if (obj instanceof Fixnum)
182: return ((Fixnum) obj).getValue() == ((LispFloat) realpart)
183: .getValue();
184: if (obj instanceof LispFloat)
185: return ((LispFloat) obj).getValue() == ((LispFloat) realpart)
186: .getValue();
187: }
188: }
189: return false;
190: }
191: signal(new TypeError(obj, "number"));
192: // Not reached.
193: return false;
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 int sxhash() throws ConditionThrowable {
216: return (mix(realpart.sxhash(), imagpart.sxhash()) & 0x7fffffff);
217: }
218:
219: public int psxhash() throws ConditionThrowable {
220: return (mix(realpart.psxhash(), imagpart.psxhash()) & 0x7fffffff);
221: }
222:
223: public String writeToString() throws ConditionThrowable {
224: StringBuffer sb = new StringBuffer("#C(");
225: sb.append(realpart.writeToString());
226: sb.append(' ');
227: sb.append(imagpart.writeToString());
228: sb.append(')');
229: return sb.toString();
230: }
231: }
|