Changeset 11729


Ignore:
Timestamp:
04/04/09 21:57:58 (12 years ago)
Author:
ehuelsmann
Message:

Fix EXPT with a Bignum exponent.
At the same time, simplify EXPT and add some documentation.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/src/org/armedbear/lisp/MathFunctions.java

    r11728 r11729  
    748748            if (base.zerop())
    749749                return base;
    750             if (power instanceof Fixnum) {
    751                 if (base.rationalp())
    752                     return intexp(base, power);
    753                 LispObject result;
    754                 if (base instanceof SingleFloat)
    755                     result = SingleFloat.ONE;
    756                 else if (base instanceof DoubleFloat)
    757                     result = DoubleFloat.ONE;
    758                 else
    759                     // base is complex
    760                     result = Fixnum.ONE;
    761                 int pow = ((Fixnum)power).value;
    762                 if (pow > 0) {
    763                     LispObject term = base;
    764                     while (pow != 0) {
    765                         if ((pow & 1) == 1)
    766                            result = result.multiplyBy(term);
    767 
    768                         term = term.multiplyBy(term);
    769                         pow = pow >> 1;
    770                     }
    771                 } else if (pow < 0) {
    772                     LispObject term = base;
    773                     pow = -pow;
    774                     while (pow != 0) {
    775                         if ((pow & 1) == 1)
    776                            result = result.divideBy(term);
    777 
    778                         term = term.multiplyBy(term);
    779                         pow = pow >> 1;
    780                     }
    781                 }
    782                 if (TRAP_OVERFLOW) {
    783                     if (result instanceof SingleFloat)
    784                         if (Float.isInfinite(((SingleFloat)result).value))
    785                             return error(new FloatingPointOverflow(NIL));
    786                     if (result instanceof DoubleFloat)
    787                         if (Double.isInfinite(((DoubleFloat)result).value))
    788                             return error(new FloatingPointOverflow(NIL));
    789                 }
    790                 if (TRAP_UNDERFLOW) {
    791                     if (result.zerop())
    792                         return error(new FloatingPointUnderflow(NIL));
    793                 }
    794                 return result;
    795             }
    796             if (base instanceof Fixnum && power instanceof Bignum)
    797                 return ((Fixnum)base).pow(power);
     750            if (base.isEqualTo(1))
     751                return base;
     752           
     753            if ((power instanceof Fixnum
     754                 || power instanceof Bignum)
     755                 && (base.rationalp()
     756                     || (base instanceof Complex
     757                         && ((Complex)base).realpart.rationalp()))) {
     758                // exact math version
     759                return intexp(base, power);
     760            }
     761            // for anything not a rational or complex rational, use
     762            // float approximation.
    798763            if (base instanceof Complex || power instanceof Complex)
    799764                return exp(power.multiplyBy(log(base)));
     
    802767            if (base instanceof Fixnum)
    803768                x = ((Fixnum)base).value;
     769            else if (base instanceof Bignum)
     770                x = ((Bignum)base).doubleValue();
    804771            else if (base instanceof Ratio)
    805772                x = ((Ratio)base).doubleValue();
     
    811778                return error(new LispError("EXPT: unsupported case: base is of type " +
    812779                                            base.typeOf().writeToString()));
    813             if (power instanceof Ratio)
     780
     781            if (power instanceof Fixnum)
     782                y = ((Fixnum)power).value;
     783            else if (power instanceof Bignum)
     784                y = ((Bignum)power).doubleValue();
     785            else if (power instanceof Ratio)
    814786                y = ((Ratio)power).doubleValue();
    815787            else if (power instanceof SingleFloat)
     
    827799                    double imagPart = r * Math.sin(y * Math.PI);
    828800                    if (base instanceof DoubleFloat || power instanceof DoubleFloat)
    829                         return Complex.getInstance(new DoubleFloat(realPart),
    830                                                    new DoubleFloat(imagPart));
     801                        return Complex
     802                            .getInstance(OverUnderFlowCheck(new DoubleFloat(realPart)),
     803                                         OverUnderFlowCheck(new DoubleFloat(imagPart)));
    831804                    else
    832                         return Complex.getInstance(new SingleFloat((float)realPart),
    833                                                    new SingleFloat((float)imagPart));
     805                        return Complex
     806                            .getInstance(OverUnderFlowCheck(new SingleFloat((float)realPart)),
     807                                         OverUnderFlowCheck(new SingleFloat((float)imagPart)));
    834808                }
    835809            }
    836810            if (base instanceof DoubleFloat || power instanceof DoubleFloat)
    837                 return new DoubleFloat(r);
     811                return OverUnderFlowCheck(new DoubleFloat(r));
    838812            else
    839                 return new SingleFloat((float)r);
    840         }
    841     };
     813                return OverUnderFlowCheck(new SingleFloat((float)r));
     814        }
     815    };
     816
     817    /** Checks number for over- or underflow values.
     818     *
     819     * @param number
     820     * @return number or signals an appropriate error
     821     * @throws org.armedbear.lisp.ConditionThrowable
     822     */
     823    private final static LispObject OverUnderFlowCheck(LispObject number)
     824            throws ConditionThrowable
     825    {
     826        if (number instanceof Complex) {
     827            OverUnderFlowCheck(((Complex)number).realpart);
     828            OverUnderFlowCheck(((Complex)number).imagpart);
     829            return number;
     830        }
     831
     832        if (TRAP_OVERFLOW) {
     833            if (number instanceof SingleFloat)
     834                if (Float.isInfinite(((SingleFloat)number).value))
     835                    return error(new FloatingPointOverflow(NIL));
     836            if (number instanceof DoubleFloat)
     837                if (Double.isInfinite(((DoubleFloat)number).value))
     838                    return error(new FloatingPointOverflow(NIL));
     839        }
     840        if (TRAP_UNDERFLOW) {
     841            if (number.zerop())
     842                return error(new FloatingPointUnderflow(NIL));
     843        }
     844        return number;
     845    }
    842846
    843847    // Adapted from SBCL.
     848    /** Return the exponent of base taken to the integer exponent power
     849     *
     850     * @param base A value of any type
     851     * @param power An integer (fixnum or bignum) value
     852     * @throws org.armedbear.lisp.ConditionThrowable
     853     */
    844854    private static final LispObject intexp(LispObject base, LispObject power)
    845855        throws ConditionThrowable
    846856    {
     857        if (power.isEqualTo(0))
     858            return Fixnum.ONE;
     859        if (base.isEqualTo(1))
     860            return base;
     861        if (base.isEqualTo(0))
     862            return base;
     863
    847864        if (power.minusp()) {
    848865            power = Fixnum.ZERO.subtract(power);
     
    851868        if (base.eql(Fixnum.TWO))
    852869            return Fixnum.ONE.ash(power);
     870
    853871        LispObject nextn = power.ash(Fixnum.MINUS_ONE);
    854872        LispObject total;
     
    861879                return total;
    862880            base = base.multiplyBy(base);
    863             power = nextn;
    864             nextn = power.ash(Fixnum.MINUS_ONE);
    865             if (power.oddp())
     881
     882            if (nextn.oddp())
    866883                total = base.multiplyBy(total);
     884            nextn = nextn.ash(Fixnum.MINUS_ONE);
    867885        }
    868886    }
Note: See TracChangeset for help on using the changeset viewer.