001: /*
002: * Math.java
003: *
004: * Copyright (C) 2004 Peter Graves
005: * $Id: MathFunctions.java,v 1.8 2004/06/10 23:21:19 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: import java.lang.reflect.Method;
025:
026: public final class MathFunctions extends Lisp {
027: // Java 1.5 provides native implementations of sinh and tanh.
028: private static final boolean isJava15;
029: static {
030: isJava15 = System.getProperty("java.version").startsWith("1.5");
031: }
032:
033: // ### sin
034: private static final Primitive1 SIN = new Primitive1("sin",
035: "radians") {
036: public LispObject execute(LispObject arg)
037: throws ConditionThrowable {
038: return sin(arg);
039: }
040: };
041:
042: private static LispObject sin(LispObject arg)
043: throws ConditionThrowable {
044: if (arg.realp())
045: return new LispFloat(Math.sin(LispFloat.coerceToFloat(arg)
046: .getValue()));
047: if (arg instanceof Complex) {
048: LispObject n = arg.multiplyBy(Complex.getInstance(
049: Fixnum.ZERO, Fixnum.ONE));
050: LispObject result = exp(n);
051: result = result
052: .subtract(exp(n.multiplyBy(Fixnum.MINUS_ONE)));
053: return result.divideBy(Fixnum.TWO.multiplyBy(Complex
054: .getInstance(Fixnum.ZERO, Fixnum.ONE)));
055: }
056: return signal(new TypeError(arg, Symbol.NUMBER));
057: }
058:
059: // ### cos
060: private static final Primitive1 COS = new Primitive1("cos",
061: "radians") {
062: public LispObject execute(LispObject arg)
063: throws ConditionThrowable {
064: return cos(arg);
065: }
066: };
067:
068: private static LispObject cos(LispObject arg)
069: throws ConditionThrowable {
070: if (arg.realp())
071: return new LispFloat(Math.cos(LispFloat.coerceToFloat(arg)
072: .getValue()));
073: if (arg instanceof Complex) {
074: LispObject n = arg.multiplyBy(Complex.getInstance(
075: Fixnum.ZERO, Fixnum.ONE));
076: LispObject result = exp(n);
077: result = result.add(exp(n.multiplyBy(Fixnum.MINUS_ONE)));
078: return result.divideBy(Fixnum.TWO);
079: }
080: return signal(new TypeError(arg, "number"));
081: }
082:
083: // ### tan
084: private static final Primitive1 TAN = new Primitive1("tan",
085: "radians") {
086: public LispObject execute(LispObject arg)
087: throws ConditionThrowable {
088: if (arg.realp())
089: return new LispFloat(Math.tan(LispFloat
090: .coerceToFloat(arg).value));
091: return sin(arg).divideBy(cos(arg));
092: }
093: };
094:
095: // ### asin
096: private static final Primitive1 ASIN = new Primitive1("asin",
097: "number") {
098: public LispObject execute(LispObject arg)
099: throws ConditionThrowable {
100: return asin(arg);
101: }
102: };
103:
104: private static LispObject asin(LispObject arg)
105: throws ConditionThrowable {
106: if (arg instanceof Complex) {
107: LispObject im = ((Complex) arg).getImaginaryPart();
108: if (im.zerop())
109: return Complex.getInstance(asin(((Complex) arg)
110: .getRealPart()), im);
111: }
112: if (arg instanceof LispFloat)
113: return new LispFloat(Math.asin(((LispFloat) arg).value));
114: LispObject result = arg.multiplyBy(arg);
115: result = Fixnum.ONE.subtract(result);
116: result = sqrt(result);
117: LispObject n = Complex.getInstance(Fixnum.ZERO, Fixnum.ONE);
118: n = n.multiplyBy(arg);
119: result = n.add(result);
120: result = log(result);
121: result = result.multiplyBy(Complex.getInstance(Fixnum.ZERO,
122: Fixnum.MINUS_ONE));
123: if (result instanceof Complex) {
124: if (arg instanceof Complex)
125: return result;
126: LispObject im = ((Complex) result).getImaginaryPart();
127: if (im.zerop())
128: return ((Complex) result).getRealPart();
129: }
130: return result;
131: }
132:
133: // ### acos
134: private static final Primitive1 ACOS = new Primitive1("acos",
135: "number") {
136: public LispObject execute(LispObject arg)
137: throws ConditionThrowable {
138: return acos(arg);
139: }
140: };
141:
142: private static LispObject acos(LispObject arg)
143: throws ConditionThrowable {
144: if (arg instanceof Complex) {
145: LispObject im = ((Complex) arg).getImaginaryPart();
146: if (im.zerop())
147: return Complex.getInstance(acos(((Complex) arg)
148: .getRealPart()), im);
149: }
150: if (arg instanceof LispFloat)
151: return new LispFloat(Math.acos(((LispFloat) arg).value));
152: LispObject result = LispFloat.PI.divideBy(Fixnum.TWO);
153: result = result.subtract(asin(arg));
154: if (result instanceof Complex) {
155: if (arg instanceof Complex)
156: return result;
157: LispObject im = ((Complex) result).getImaginaryPart();
158: if (im.zerop())
159: return ((Complex) result).getRealPart();
160: }
161: return result;
162: }
163:
164: // ### atan
165: private static final Primitive ATAN = new Primitive("atan",
166: "number1 &optional number2") {
167: public LispObject execute(LispObject arg)
168: throws ConditionThrowable {
169: return atan(arg);
170: }
171:
172: public LispObject execute(LispObject first, LispObject second)
173: throws ConditionThrowable {
174: return atan(first.divideBy(second));
175: }
176: };
177:
178: private static LispObject atan(LispObject arg)
179: throws ConditionThrowable {
180: if (arg instanceof Complex) {
181: LispObject im = ((Complex) arg).getImaginaryPart();
182: if (im.zerop())
183: return Complex.getInstance(atan(((Complex) arg)
184: .getRealPart()), im);
185: LispObject result = arg.multiplyBy(arg);
186: result = result.add(Fixnum.ONE);
187: result = Fixnum.ONE.divideBy(result);
188: result = sqrt(result);
189: LispObject n = Complex.getInstance(Fixnum.ZERO, Fixnum.ONE);
190: n = n.multiplyBy(arg);
191: n = n.add(Fixnum.ONE);
192: result = n.multiplyBy(result);
193: result = log(result);
194: result = result.multiplyBy(Complex.getInstance(Fixnum.ZERO,
195: Fixnum.MINUS_ONE));
196: return result;
197: }
198: return new LispFloat(Math.atan(LispFloat.coerceToFloat(arg)
199: .getValue()));
200: }
201:
202: // ### sinh
203: private static final Primitive1 SINH = new Primitive1("sinh",
204: "number") {
205: public LispObject execute(LispObject arg)
206: throws ConditionThrowable {
207: return sinh(arg);
208: }
209: };
210:
211: private static Method sinhMethod = null;
212:
213: private static LispObject sinh(LispObject arg)
214: throws ConditionThrowable {
215: if (arg instanceof Complex) {
216: LispObject im = ((Complex) arg).getImaginaryPart();
217: if (im.zerop())
218: return Complex.getInstance(sinh(((Complex) arg)
219: .getRealPart()), im);
220: }
221: if (isJava15 && arg instanceof LispFloat) {
222: try {
223: if (sinhMethod == null) {
224: Class c = Class.forName("java.lang.Math");
225: Class[] parameterTypes = new Class[1];
226: parameterTypes[0] = Double.TYPE;
227: sinhMethod = c.getMethod("sinh", parameterTypes);
228: }
229: if (sinhMethod != null) {
230: Object[] args;
231: args = new Object[1];
232: args[0] = new Double(((LispFloat) arg).value);
233: Double d = (Double) sinhMethod.invoke(null, args);
234: return new LispFloat(d.doubleValue());
235: }
236: } catch (Throwable t) {
237: Debug.trace(t);
238: // Fall through...
239: }
240: }
241: LispObject result = exp(arg);
242: result = result.subtract(exp(arg.multiplyBy(Fixnum.MINUS_ONE)));
243: result = result.divideBy(Fixnum.TWO);
244: if (result instanceof Complex) {
245: if (arg instanceof Complex)
246: return result;
247: LispObject im = ((Complex) result).getImaginaryPart();
248: if (im.zerop())
249: return ((Complex) result).getRealPart();
250: }
251: return result;
252: }
253:
254: // ### cosh
255: private static final Primitive1 COSH = new Primitive1("cosh",
256: "number") {
257: public LispObject execute(LispObject arg)
258: throws ConditionThrowable {
259: return cosh(arg);
260: }
261: };
262:
263: private static Method coshMethod = null;
264:
265: private static LispObject cosh(LispObject arg)
266: throws ConditionThrowable {
267: if (arg instanceof Complex) {
268: LispObject im = ((Complex) arg).getImaginaryPart();
269: if (im.zerop())
270: return Complex.getInstance(cosh(((Complex) arg)
271: .getRealPart()), im);
272: }
273: if (isJava15 && arg instanceof LispFloat) {
274: try {
275: if (coshMethod == null) {
276: Class c = Class.forName("java.lang.Math");
277: Class[] parameterTypes = new Class[1];
278: parameterTypes[0] = Double.TYPE;
279: coshMethod = c.getMethod("cosh", parameterTypes);
280: }
281: if (coshMethod != null) {
282: Object[] args;
283: args = new Object[1];
284: args[0] = new Double(((LispFloat) arg).value);
285: Double d = (Double) coshMethod.invoke(null, args);
286: return new LispFloat(d.doubleValue());
287: }
288: } catch (Throwable t) {
289: Debug.trace(t);
290: // Fall through...
291: }
292: }
293: LispObject result = exp(arg);
294: result = result.add(exp(arg.multiplyBy(Fixnum.MINUS_ONE)));
295: result = result.divideBy(Fixnum.TWO);
296: if (result instanceof Complex) {
297: if (arg instanceof Complex)
298: return result;
299: LispObject im = ((Complex) result).getImaginaryPart();
300: if (im.zerop())
301: return ((Complex) result).getRealPart();
302: }
303: return result;
304: }
305:
306: private static Method tanhMethod = null;
307:
308: // ### tanh
309: private static final Primitive1 TANH = new Primitive1("tanh",
310: "number") {
311: public LispObject execute(LispObject arg)
312: throws ConditionThrowable {
313: if (isJava15 && arg instanceof LispFloat) {
314: try {
315: if (tanhMethod == null) {
316: Class c = Class.forName("java.lang.Math");
317: Class[] parameterTypes = new Class[1];
318: parameterTypes[0] = Double.TYPE;
319: tanhMethod = c
320: .getMethod("tanh", parameterTypes);
321: }
322: if (tanhMethod != null) {
323: Object[] args;
324: args = new Object[1];
325: args[0] = new Double(((LispFloat) arg).value);
326: Double d = (Double) tanhMethod.invoke(null,
327: args);
328: return new LispFloat(d.doubleValue());
329: }
330: } catch (Throwable t) {
331: Debug.trace(t);
332: // Fall through...
333: }
334: }
335: return sinh(arg).divideBy(cosh(arg));
336: }
337: };
338:
339: // ### asinh
340: private static final Primitive1 ASINH = new Primitive1("asinh",
341: "number") {
342: public LispObject execute(LispObject arg)
343: throws ConditionThrowable {
344: return asinh(arg);
345: }
346: };
347:
348: private static LispObject asinh(LispObject arg)
349: throws ConditionThrowable {
350: if (arg instanceof Complex) {
351: LispObject im = ((Complex) arg).getImaginaryPart();
352: if (im.zerop())
353: return Complex.getInstance(asinh(((Complex) arg)
354: .getRealPart()), im);
355: }
356: LispObject result = arg.multiplyBy(arg);
357: result = Fixnum.ONE.add(result);
358: result = sqrt(result);
359: result = result.add(arg);
360: result = log(result);
361: if (result instanceof Complex) {
362: if (arg instanceof Complex)
363: return result;
364: LispObject im = ((Complex) result).getImaginaryPart();
365: if (im.zerop())
366: return ((Complex) result).getRealPart();
367: }
368: return result;
369: }
370:
371: // ### acosh
372: private static final Primitive1 ACOSH = new Primitive1("acosh",
373: "number") {
374: public LispObject execute(LispObject arg)
375: throws ConditionThrowable {
376: return acosh(arg);
377: }
378: };
379:
380: private static LispObject acosh(LispObject arg)
381: throws ConditionThrowable {
382: if (arg instanceof Complex) {
383: LispObject im = ((Complex) arg).getImaginaryPart();
384: if (im.zerop())
385: return Complex.getInstance(acosh(((Complex) arg)
386: .getRealPart()), im);
387: }
388: LispObject n1 = arg.add(Fixnum.ONE);
389: n1 = n1.divideBy(Fixnum.TWO);
390: n1 = sqrt(n1);
391: LispObject n2 = arg.subtract(Fixnum.ONE);
392: n2 = n2.divideBy(Fixnum.TWO);
393: n2 = sqrt(n2);
394: LispObject result = n1.add(n2);
395: result = log(result);
396: result = result.multiplyBy(Fixnum.TWO);
397: if (result instanceof Complex) {
398: if (arg instanceof Complex)
399: return result;
400: LispObject im = ((Complex) result).getImaginaryPart();
401: if (im.zerop())
402: return ((Complex) result).getRealPart();
403: }
404: return result;
405: }
406:
407: // ### atanh
408: private static final Primitive1 ATANH = new Primitive1("atanh",
409: "number") {
410: public LispObject execute(LispObject arg)
411: throws ConditionThrowable {
412: return atanh(arg);
413: }
414: };
415:
416: private static LispObject atanh(LispObject arg)
417: throws ConditionThrowable {
418: if (arg instanceof Complex) {
419: LispObject im = ((Complex) arg).getImaginaryPart();
420: if (im.zerop())
421: return Complex.getInstance(atanh(((Complex) arg)
422: .getRealPart()), im);
423: }
424: LispObject n1 = log(Fixnum.ONE.add(arg));
425: LispObject n2 = log(Fixnum.ONE.subtract(arg));
426: LispObject result = n1.subtract(n2);
427: result = result.divideBy(Fixnum.TWO);
428: if (result instanceof Complex) {
429: if (arg instanceof Complex)
430: return result;
431: LispObject im = ((Complex) result).getImaginaryPart();
432: if (im.zerop())
433: return ((Complex) result).getRealPart();
434: }
435: return result;
436: }
437:
438: // ### exp
439: private static final Primitive1 EXP = new Primitive1("exp",
440: "number") {
441: public LispObject execute(LispObject arg)
442: throws ConditionThrowable {
443: return exp(arg);
444: }
445: };
446:
447: private static LispObject exp(LispObject arg)
448: throws ConditionThrowable {
449: if (arg instanceof LispFloat)
450: return new LispFloat(Math.exp(((LispFloat) arg).value));
451: if (arg.realp())
452: return new LispFloat(Math
453: .exp(LispFloat.coerceToFloat(arg).value));
454: if (arg instanceof Complex) {
455: Complex argc = (Complex) arg;
456: double re = LispFloat.coerceToFloat(argc.getRealPart())
457: .getValue();
458: double im = LispFloat
459: .coerceToFloat(argc.getImaginaryPart()).getValue();
460: LispFloat resX = new LispFloat(Math.exp(re) * Math.cos(im));
461: LispFloat resY = new LispFloat(Math.exp(re) * Math.sin(im));
462: return Complex.getInstance(resX, resY);
463: }
464: return signal(new TypeError(arg, Symbol.NUMBER));
465: }
466:
467: // ### sqrt
468: private static final Primitive1 SQRT = new Primitive1("sqrt",
469: "number") {
470: public LispObject execute(LispObject arg)
471: throws ConditionThrowable {
472: return sqrt(arg);
473: }
474: };
475:
476: private static final LispObject sqrt(LispObject obj)
477: throws ConditionThrowable {
478: if (obj.realp() && !obj.minusp()) { // returning real
479: LispFloat f = LispFloat.coerceToFloat(obj);
480: return new LispFloat(Math.sqrt(f.getValue()));
481: } else { // returning Complex
482: if (obj.realp()) {
483: return Complex.getInstance(new LispFloat(0),
484: sqrt(Fixnum.ZERO.subtract(obj)));
485: } else if (obj instanceof Complex) {
486: return exp(log(obj).divideBy(Fixnum.TWO));
487: }
488: }
489: signal(new TypeError(obj, "number"));
490: return NIL;
491: }
492:
493: // ### log
494: private static final Primitive LOG = new Primitive("log",
495: "number &optional base") {
496: public LispObject execute(LispObject arg)
497: throws ConditionThrowable {
498: return log(arg);
499: }
500:
501: public LispObject execute(LispObject number, LispObject base)
502: throws ConditionThrowable {
503: return log(number).divideBy(log(base));
504: }
505: };
506:
507: private static final LispObject log(LispObject obj)
508: throws ConditionThrowable {
509: if (obj.realp() && !obj.minusp()) { // real value
510: if (obj instanceof Fixnum)
511: return new LispFloat(Math
512: .log(((Fixnum) obj).getValue()));
513: if (obj instanceof Bignum)
514: return new LispFloat(Math.log(((Bignum) obj)
515: .floatValue()));
516: if (obj instanceof Ratio)
517: return new LispFloat(Math.log(((Ratio) obj)
518: .floatValue()));
519: if (obj instanceof LispFloat)
520: return new LispFloat(Math.log(((LispFloat) obj)
521: .getValue()));
522: } else { // returning Complex
523: LispFloat re, im, phase, abs;
524: if (obj.realp() && obj.minusp()) {
525: re = LispFloat.coerceToFloat(obj);
526: abs = new LispFloat(Math.abs(re.getValue()));
527: phase = new LispFloat(Math.PI);
528: return Complex.getInstance(new LispFloat(Math.log(abs
529: .getValue())), phase);
530: } else if (obj instanceof Complex) {
531: re = LispFloat.coerceToFloat(((Complex) obj)
532: .getRealPart());
533: im = LispFloat.coerceToFloat(((Complex) obj)
534: .getImaginaryPart());
535: phase = new LispFloat(Math.atan2(im.getValue(), re
536: .getValue())); // atan(y/x)
537: abs = (LispFloat) ((Complex) obj).ABS();
538: return Complex.getInstance(new LispFloat(Math.log(abs
539: .getValue())), phase);
540: }
541: }
542: signal(new TypeError(obj, "number"));
543: return NIL;
544: }
545: }
|