source: trunk/abcl/src/org/armedbear/lisp/SingleFloat.java @ 11490

Last change on this file since 11490 was 11488, checked in by ehuelsmann, 16 years ago

Add @Override annotations.

Patch by: Douglas Miles

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.7 KB
Line 
1/*
2 * SingleFloat.java
3 *
4 * Copyright (C) 2003-2007 Peter Graves
5 * $Id: SingleFloat.java 11488 2008-12-27 10:50:33Z 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 java.math.BigInteger;
37
38public final class SingleFloat extends LispObject
39{
40    public static final SingleFloat ZERO       = new SingleFloat(0);
41    public static final SingleFloat MINUS_ZERO = new SingleFloat(-0.0f);
42    public static final SingleFloat ONE        = new SingleFloat(1);
43    public static final SingleFloat MINUS_ONE  = new SingleFloat(-1);
44
45    public static final SingleFloat SINGLE_FLOAT_POSITIVE_INFINITY =
46        new SingleFloat(Float.POSITIVE_INFINITY);
47
48    public static final SingleFloat SINGLE_FLOAT_NEGATIVE_INFINITY =
49        new SingleFloat(Float.NEGATIVE_INFINITY);
50
51    static {
52        Symbol.SINGLE_FLOAT_POSITIVE_INFINITY.initializeConstant(SINGLE_FLOAT_POSITIVE_INFINITY);
53        Symbol.SINGLE_FLOAT_NEGATIVE_INFINITY.initializeConstant(SINGLE_FLOAT_NEGATIVE_INFINITY);
54    }
55
56    public final float value;
57
58    public SingleFloat(float value)
59    {
60        this.value = value;
61    }
62
63    @Override
64    public LispObject typeOf()
65    {
66        return Symbol.SINGLE_FLOAT;
67    }
68
69    @Override
70    public LispObject classOf()
71    {
72        return BuiltInClass.SINGLE_FLOAT;
73    }
74
75    @Override
76    public LispObject typep(LispObject typeSpecifier) throws ConditionThrowable
77    {
78        if (typeSpecifier == Symbol.FLOAT)
79            return T;
80        if (typeSpecifier == Symbol.REAL)
81            return T;
82        if (typeSpecifier == Symbol.NUMBER)
83            return T;
84        if (typeSpecifier == Symbol.SINGLE_FLOAT)
85            return T;
86        if (typeSpecifier == Symbol.SHORT_FLOAT)
87            return T;
88        if (typeSpecifier == BuiltInClass.FLOAT)
89            return T;
90        if (typeSpecifier == BuiltInClass.SINGLE_FLOAT)
91            return T;
92        return super.typep(typeSpecifier);
93    }
94
95    @Override
96    public LispObject NUMBERP()
97    {
98        return T;
99    }
100
101    @Override
102    public boolean numberp()
103    {
104        return true;
105    }
106
107    @Override
108    public boolean realp()
109    {
110        return true;
111    }
112
113    @Override
114    public boolean eql(LispObject obj)
115    {
116        if (this == obj)
117            return true;
118        if (obj instanceof SingleFloat) {
119            if (value == 0) {
120                // "If an implementation supports positive and negative zeros
121                // as distinct values, then (EQL 0.0 -0.0) returns false."
122                float f = ((SingleFloat)obj).value;
123                int bits = Float.floatToRawIntBits(f);
124                return bits == Float.floatToRawIntBits(value);
125            }
126            if (value == ((SingleFloat)obj).value)
127                return true;
128        }
129        return false;
130    }
131
132    @Override
133    public boolean equal(LispObject obj)
134    {
135        if (this == obj)
136            return true;
137        if (obj instanceof SingleFloat) {
138            if (value == 0) {
139                // same as EQL
140                float f = ((SingleFloat)obj).value;
141                int bits = Float.floatToRawIntBits(f);
142                return bits == Float.floatToRawIntBits(value);
143            }
144            if (value == ((SingleFloat)obj).value)
145                return true;
146        }
147        return false;
148    }
149
150    @Override
151    public boolean equalp(int n)
152    {
153        // "If two numbers are the same under =."
154        return value == n;
155    }
156
157    @Override
158    public boolean equalp(LispObject obj) throws ConditionThrowable
159    {
160        if (obj instanceof SingleFloat)
161            return value == ((SingleFloat)obj).value;
162        if (obj instanceof DoubleFloat)
163            return value == ((DoubleFloat)obj).value;
164        if (obj instanceof Fixnum)
165            return value == ((Fixnum)obj).value;
166        if (obj instanceof Bignum)
167            return value == ((Bignum)obj).floatValue();
168        if (obj instanceof Ratio)
169            return value == ((Ratio)obj).floatValue();
170        return false;
171    }
172
173    @Override
174    public LispObject ABS()
175    {
176        if (value > 0)
177            return this;
178        if (value == 0) // 0.0 or -0.0
179            return ZERO;
180        return new SingleFloat(- value);
181    }
182
183    @Override
184    public boolean plusp()
185    {
186        return value > 0;
187    }
188
189    @Override
190    public boolean minusp()
191    {
192        return value < 0;
193    }
194
195    @Override
196    public boolean zerop()
197    {
198        return value == 0;
199    }
200
201    @Override
202    public LispObject FLOATP()
203    {
204        return T;
205    }
206
207    @Override
208    public boolean floatp()
209    {
210        return true;
211    }
212
213    public static double getValue(LispObject obj) throws ConditionThrowable
214    {
215        try {
216            return ((SingleFloat)obj).value;
217        }
218        catch (ClassCastException e) {
219            error(new TypeError(obj, Symbol.FLOAT));
220            // Not reached.
221            return 0;
222        }
223    }
224
225    public final float getValue()
226    {
227        return value;
228    }
229
230    @Override
231    public Object javaInstance()
232    {
233        return Float.valueOf(value);
234    }
235
236    @Override
237    public Object javaInstance(Class c)
238    {
239        String cn = c.getName();
240        if (cn.equals("java.lang.Float") || cn.equals("float"))
241            return Float.valueOf(value);
242        return javaInstance();
243    }
244
245    @Override
246    public final LispObject incr()
247    {
248        return new SingleFloat(value + 1);
249    }
250
251    @Override
252    public final LispObject decr()
253    {
254        return new SingleFloat(value - 1);
255    }
256
257    @Override
258    public LispObject add(LispObject obj) throws ConditionThrowable
259    {
260        if (obj instanceof Fixnum)
261            return new SingleFloat(value + ((Fixnum)obj).value);
262        if (obj instanceof SingleFloat)
263            return new SingleFloat(value + ((SingleFloat)obj).value);
264        if (obj instanceof DoubleFloat)
265            return new DoubleFloat(value + ((DoubleFloat)obj).value);
266        if (obj instanceof Bignum)
267            return new SingleFloat(value + ((Bignum)obj).floatValue());
268        if (obj instanceof Ratio)
269            return new SingleFloat(value + ((Ratio)obj).floatValue());
270        if (obj instanceof Complex) {
271            Complex c = (Complex) obj;
272            return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart());
273        }
274        return error(new TypeError(obj, Symbol.NUMBER));
275    }
276
277    @Override
278    public LispObject negate()
279    {
280        if (value == 0) {
281            int bits = Float.floatToRawIntBits(value);
282            return (bits < 0) ? ZERO : MINUS_ZERO;
283        }
284        return new SingleFloat(-value);
285    }
286
287    @Override
288    public LispObject subtract(LispObject obj) throws ConditionThrowable
289    {
290        if (obj instanceof Fixnum)
291            return new SingleFloat(value - ((Fixnum)obj).value);
292        if (obj instanceof SingleFloat)
293            return new SingleFloat(value - ((SingleFloat)obj).value);
294        if (obj instanceof DoubleFloat)
295            return new DoubleFloat(value - ((DoubleFloat)obj).value);
296        if (obj instanceof Bignum)
297            return new SingleFloat(value - ((Bignum)obj).floatValue());
298        if (obj instanceof Ratio)
299            return new SingleFloat(value - ((Ratio)obj).floatValue());
300        if (obj instanceof Complex) {
301            Complex c = (Complex) obj;
302            return Complex.getInstance(subtract(c.getRealPart()),
303                                       ZERO.subtract(c.getImaginaryPart()));
304        }
305        return error(new TypeError(obj, Symbol.NUMBER));
306    }
307
308    @Override
309    public LispObject multiplyBy(LispObject obj) throws ConditionThrowable
310    {
311        if (obj instanceof Fixnum)
312            return new SingleFloat(value * ((Fixnum)obj).value);
313        if (obj instanceof SingleFloat)
314            return new SingleFloat(value * ((SingleFloat)obj).value);
315        if (obj instanceof DoubleFloat)
316            return new DoubleFloat(value * ((DoubleFloat)obj).value);
317        if (obj instanceof Bignum)
318            return new SingleFloat(value * ((Bignum)obj).floatValue());
319        if (obj instanceof Ratio)
320            return new SingleFloat(value * ((Ratio)obj).floatValue());
321        if (obj instanceof Complex) {
322            Complex c = (Complex) obj;
323            return Complex.getInstance(multiplyBy(c.getRealPart()),
324                                       multiplyBy(c.getImaginaryPart()));
325        }
326        return error(new TypeError(obj, Symbol.NUMBER));
327    }
328
329    @Override
330    public LispObject divideBy(LispObject obj) throws ConditionThrowable
331    {
332        if (obj instanceof Fixnum)
333            return new SingleFloat(value / ((Fixnum)obj).value);
334        if (obj instanceof SingleFloat)
335            return new SingleFloat(value / ((SingleFloat)obj).value);
336        if (obj instanceof DoubleFloat)
337            return new DoubleFloat(value / ((DoubleFloat)obj).value);
338        if (obj instanceof Bignum)
339            return new SingleFloat(value / ((Bignum)obj).floatValue());
340        if (obj instanceof Ratio)
341            return new SingleFloat(value / ((Ratio)obj).floatValue());
342        if (obj instanceof Complex) {
343            Complex c = (Complex) obj;
344            LispObject re = c.getRealPart();
345            LispObject im = c.getImaginaryPart();
346            LispObject denom = re.multiplyBy(re).add(im.multiplyBy(im));
347            LispObject resX = multiplyBy(re).divideBy(denom);
348            LispObject resY =
349                multiplyBy(Fixnum.MINUS_ONE).multiplyBy(im).divideBy(denom);
350            return Complex.getInstance(resX, resY);
351        }
352        return error(new TypeError(obj, Symbol.NUMBER));
353    }
354
355    @Override
356    public boolean isEqualTo(LispObject obj) throws ConditionThrowable
357    {
358        if (obj instanceof Fixnum)
359            return rational().isEqualTo(obj);
360        if (obj instanceof SingleFloat)
361            return value == ((SingleFloat)obj).value;
362        if (obj instanceof DoubleFloat)
363            return value == ((DoubleFloat)obj).value;
364        if (obj instanceof Bignum)
365            return rational().isEqualTo(obj);
366        if (obj instanceof Ratio)
367            return rational().isEqualTo(obj);
368        if (obj instanceof Complex)
369            return obj.isEqualTo(this);
370        error(new TypeError(obj, Symbol.NUMBER));
371        // Not reached.
372        return false;
373    }
374
375    @Override
376    public boolean isNotEqualTo(LispObject obj) throws ConditionThrowable
377    {
378        return !isEqualTo(obj);
379    }
380
381    @Override
382    public boolean isLessThan(LispObject obj) throws ConditionThrowable
383    {
384        if (obj instanceof Fixnum)
385            return rational().isLessThan(obj);
386        if (obj instanceof SingleFloat)
387            return value < ((SingleFloat)obj).value;
388        if (obj instanceof DoubleFloat)
389            return value < ((DoubleFloat)obj).value;
390        if (obj instanceof Bignum)
391            return rational().isLessThan(obj);
392        if (obj instanceof Ratio)
393            return rational().isLessThan(obj);
394        error(new TypeError(obj, Symbol.REAL));
395        // Not reached.
396        return false;
397    }
398
399    @Override
400    public boolean isGreaterThan(LispObject obj) throws ConditionThrowable
401    {
402        if (obj instanceof Fixnum)
403            return rational().isGreaterThan(obj);
404        if (obj instanceof SingleFloat)
405            return value > ((SingleFloat)obj).value;
406        if (obj instanceof DoubleFloat)
407            return value > ((DoubleFloat)obj).value;
408        if (obj instanceof Bignum)
409            return rational().isGreaterThan(obj);
410        if (obj instanceof Ratio)
411            return rational().isGreaterThan(obj);
412        error(new TypeError(obj, Symbol.REAL));
413        // Not reached.
414        return false;
415    }
416
417    @Override
418    public boolean isLessThanOrEqualTo(LispObject obj) throws ConditionThrowable
419    {
420        if (obj instanceof Fixnum)
421            return rational().isLessThanOrEqualTo(obj);
422        if (obj instanceof SingleFloat)
423            return value <= ((SingleFloat)obj).value;
424        if (obj instanceof DoubleFloat)
425            return value <= ((DoubleFloat)obj).value;
426        if (obj instanceof Bignum)
427            return rational().isLessThanOrEqualTo(obj);
428        if (obj instanceof Ratio)
429            return rational().isLessThanOrEqualTo(obj);
430        error(new TypeError(obj, Symbol.REAL));
431        // Not reached.
432        return false;
433    }
434
435    @Override
436    public boolean isGreaterThanOrEqualTo(LispObject obj) throws ConditionThrowable
437    {
438        if (obj instanceof Fixnum)
439            return rational().isGreaterThanOrEqualTo(obj);
440        if (obj instanceof SingleFloat)
441            return value >= ((SingleFloat)obj).value;
442        if (obj instanceof DoubleFloat)
443            return value >= ((DoubleFloat)obj).value;
444        if (obj instanceof Bignum)
445            return rational().isGreaterThanOrEqualTo(obj);
446        if (obj instanceof Ratio)
447            return rational().isGreaterThanOrEqualTo(obj);
448        error(new TypeError(obj, Symbol.REAL));
449        // Not reached.
450        return false;
451    }
452
453    @Override
454    public LispObject truncate(LispObject obj) throws ConditionThrowable
455    {
456        // "When rationals and floats are combined by a numerical function,
457        // the rational is first converted to a float of the same format."
458        // 12.1.4.1
459        if (obj instanceof Fixnum) {
460            return truncate(new SingleFloat(((Fixnum)obj).value));
461        }
462        if (obj instanceof Bignum) {
463            return truncate(new SingleFloat(((Bignum)obj).floatValue()));
464        }
465        if (obj instanceof Ratio) {
466            return truncate(new SingleFloat(((Ratio)obj).floatValue()));
467        }
468        if (obj instanceof SingleFloat) {
469            final LispThread thread = LispThread.currentThread();
470            float divisor = ((SingleFloat)obj).value;
471            float quotient = value / divisor;
472            if (quotient >= Integer.MIN_VALUE && quotient <= Integer.MAX_VALUE) {
473                int q = (int) quotient;
474                return thread.setValues(new Fixnum(q),
475                                        new SingleFloat(value - q * divisor));
476            }
477            // We need to convert the quotient to a bignum.
478            int bits = Float.floatToRawIntBits(quotient);
479            int s = ((bits >> 31) == 0) ? 1 : -1;
480            int e = (int) ((bits >> 23) & 0xff);
481            long m;
482            if (e == 0)
483                m = (bits & 0x7fffff) << 1;
484            else
485                m = (bits & 0x7fffff) | 0x800000;
486            LispObject significand = number(m);
487            Fixnum exponent = new Fixnum(e - 150);
488            Fixnum sign = new Fixnum(s);
489            LispObject result = significand;
490            result =
491                result.multiplyBy(MathFunctions.EXPT.execute(Fixnum.TWO, exponent));
492            result = result.multiplyBy(sign);
493            // Calculate remainder.
494            LispObject product = result.multiplyBy(obj);
495            LispObject remainder = subtract(product);
496            return thread.setValues(result, remainder);
497        }
498        if (obj instanceof DoubleFloat) {
499            final LispThread thread = LispThread.currentThread();
500            double divisor = ((DoubleFloat)obj).value;
501            double quotient = value / divisor;
502            if (quotient >= Integer.MIN_VALUE && quotient <= Integer.MAX_VALUE) {
503                int q = (int) quotient;
504                return thread.setValues(new Fixnum(q),
505                                        new DoubleFloat(value - q * divisor));
506            }
507            // We need to convert the quotient to a bignum.
508            long bits = Double.doubleToRawLongBits((double)quotient);
509            int s = ((bits >> 63) == 0) ? 1 : -1;
510            int e = (int) ((bits >> 52) & 0x7ffL);
511            long m;
512            if (e == 0)
513                m = (bits & 0xfffffffffffffL) << 1;
514            else
515                m = (bits & 0xfffffffffffffL) | 0x10000000000000L;
516            LispObject significand = number(m);
517            Fixnum exponent = new Fixnum(e - 1075);
518            Fixnum sign = new Fixnum(s);
519            LispObject result = significand;
520            result =
521                result.multiplyBy(MathFunctions.EXPT.execute(Fixnum.TWO, exponent));
522            result = result.multiplyBy(sign);
523            // Calculate remainder.
524            LispObject product = result.multiplyBy(obj);
525            LispObject remainder = subtract(product);
526            return thread.setValues(result, remainder);
527        }
528        return error(new TypeError(obj, Symbol.REAL));
529    }
530
531    @Override
532    public int hashCode()
533    {
534        return Float.floatToIntBits(value);
535    }
536
537    @Override
538    public int psxhash()
539    {
540        if ((value % 1) == 0)
541            return (((int)value) & 0x7fffffff);
542        else
543            return (hashCode() & 0x7fffffff);
544    }
545
546    @Override
547    public String writeToString() throws ConditionThrowable
548    {
549        if (value == Float.POSITIVE_INFINITY) {
550            StringBuffer sb = new StringBuffer("#.");
551            sb.append(Symbol.SINGLE_FLOAT_POSITIVE_INFINITY.writeToString());
552            return sb.toString();
553        }
554        if (value == Float.NEGATIVE_INFINITY) {
555            StringBuffer sb = new StringBuffer("#.");
556            sb.append(Symbol.SINGLE_FLOAT_NEGATIVE_INFINITY.writeToString());
557            return sb.toString();
558        }
559        if (value != value)
560            return "#<SINGLE-FLOAT NaN>";
561        String s1 = String.valueOf(value);
562        LispThread thread = LispThread.currentThread();
563        if (Symbol.PRINT_READABLY.symbolValue(thread) != NIL ||
564            !memq(Symbol.READ_DEFAULT_FLOAT_FORMAT.symbolValue(thread),
565                  list2(Symbol.SINGLE_FLOAT, Symbol.SHORT_FLOAT)))
566        {
567            if (s1.indexOf('E') >= 0)
568                return s1.replace('E', 'f');
569            else
570                return s1.concat("f0");
571        } else
572            return s1;
573    }
574
575    public LispObject rational() throws ConditionThrowable
576    {
577        final int bits = Float.floatToRawIntBits(value);
578        int sign = ((bits >> 31) == 0) ? 1 : -1;
579        int storedExponent = ((bits >> 23) & 0xff);
580        long mantissa;
581        if (storedExponent == 0)
582            mantissa = (bits & 0x7fffff) << 1;
583        else
584            mantissa = (bits & 0x7fffff) | 0x800000;
585        if (mantissa == 0)
586            return Fixnum.ZERO;
587        if (sign < 0)
588            mantissa = -mantissa;
589        // Subtract bias.
590        final int exponent = storedExponent - 127;
591        BigInteger numerator, denominator;
592        if (exponent < 0) {
593            numerator = BigInteger.valueOf(mantissa);
594            denominator = BigInteger.valueOf(1).shiftLeft(23 - exponent);
595        } else {
596            numerator = BigInteger.valueOf(mantissa).shiftLeft(exponent);
597            denominator = BigInteger.valueOf(0x800000); // (ash 1 23)
598        }
599        return number(numerator, denominator);
600    }
601
602    public static SingleFloat coerceToFloat(LispObject obj) throws ConditionThrowable
603    {
604        if (obj instanceof Fixnum)
605            return new SingleFloat(((Fixnum)obj).value);
606        if (obj instanceof SingleFloat)
607            return (SingleFloat) obj;
608        if (obj instanceof DoubleFloat)
609            return new SingleFloat((float)((DoubleFloat)obj).value);
610        if (obj instanceof Bignum)
611            return new SingleFloat(((Bignum)obj).floatValue());
612        if (obj instanceof Ratio)
613            return new SingleFloat(((Ratio)obj).floatValue());
614        error(new TypeError("The value " + obj.writeToString() +
615                             " cannot be converted to type SINGLE-FLOAT."));
616        // Not reached.
617        return null;
618    }
619}
Note: See TracBrowser for help on using the repository browser.