Package xbird.xquery.operator.math

Source Code of xbird.xquery.operator.math.DivOp$DivDouble

/*
* @(#)$Id: DivOp.java 3619 2008-03-26 07:23:03Z yui $
*
* Copyright 2006-2008 Makoto YUI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
*     Makoto YUI - initial implementation
*/
package xbird.xquery.operator.math;

import java.math.BigDecimal;

import xbird.util.struct.Pair;
import xbird.xquery.DynamicError;
import xbird.xquery.XQueryException;
import xbird.xquery.dm.value.*;
import xbird.xquery.dm.value.literal.*;
import xbird.xquery.dm.value.sequence.ValueSequence;
import xbird.xquery.dm.value.xsi.DurationValue;
import xbird.xquery.meta.DynamicContext;
import xbird.xquery.meta.StaticContext;
import xbird.xquery.misc.TypeUtil;
import xbird.xquery.operator.InternalFunction;
import xbird.xquery.type.*;
import xbird.xquery.type.xs.*;

/**
* fs:div(A, B).
* <DIV lang="en">
* <u>denotes</u>
* <ul>
* Numeric / Numeric<br/>
<li>op:numeric-divide(xs:integer, xs:integer) as xs:double</li>
<li>op:numeric-divide(xs:decimal, xs:decimal) as xs:decimal</li>
<li>op:numeric-divide(xs:float, xs:float) as xs:float</li>
<li>op:numeric-divide(xs:double, xs:double) as xs:double</li>
* <br/>Duration / Numeric<br/>
<li>op:divide-yearMonthDuration(xdt:yearMonthDuration, xs:double) as xdt:yearMonthDuration</li>
<li>op:divide-dayTimeDuration(xdt:dayTimeDuration, xs:double) as xdt:dayTimeDuration</li>
* <br/>Duration / Duration<br/>
<li>op:divide-yearMonthDuration-by-yearMonthDuration(xdt:yearMonthDuration, xdt:yearMonthDuration) as xs:decimal</li>
<li>op:divide-dayTimeDuration-by-dayTimeDuration(xdt:dayTimeDuration, xdt:dayTimeDuration) as xs:decimal</li>
* </ul>
* </DIV>
* <DIV lang="ja"></DIV>
*
* @author Makoto YUI (yuin405+xbird@gmail.com)
* @link http://www.w3.org/TR/xpath-functions/#func-numeric-divide
* @link http://www.w3.org/TR/xquery-operators/#op.numeric
*/
public class DivOp extends NumericOp {
    private static final long serialVersionUID = -3633714711839515327L;
    public static final String SYMBOL = "fs:div";

    public DivOp() {
        super(SYMBOL);
    }

    @SuppressWarnings("unchecked")
    protected Pair<AtomicType[], AtomicType>[] signatures() {
        final Pair<AtomicType[], AtomicType>[] s = new Pair[] {
                // op:numeric-divide(xs:integer, xs:integer) as xs:double
                // As a special case, if the types of both $arg1 and $arg2 are xs:integer, then the return type is xs:decimal.
                new Pair(new AtomicType[] { IntegerType.INTEGER, IntegerType.INTEGER }, DecimalType.DECIMAL),
                // op:numeric-divide(xs:decimal, xs:decimal) as xs:decimal
                new Pair(new AtomicType[] { DecimalType.DECIMAL, DecimalType.DECIMAL }, DecimalType.DECIMAL),
                // op:numeric-divide(xs:float, xs:float) as xs:float
                new Pair(new AtomicType[] { FloatType.FLOAT, FloatType.FLOAT }, FloatType.FLOAT),
                // workaround
                new Pair(new AtomicType[] { DecimalType.DECIMAL, FloatType.FLOAT }, FloatType.FLOAT),
                new Pair(new AtomicType[] { FloatType.FLOAT, DecimalType.DECIMAL }, FloatType.FLOAT),
                // op:numeric-divide(xs:double, xs:double) as xs:double
                new Pair(new AtomicType[] { DoubleType.DOUBLE, DoubleType.DOUBLE }, DoubleType.DOUBLE),
                // op:divide-yearMonthDuration(xdt:yearMonthDuration, xs:double) as xdt:yearMonthDuration
                new Pair(new AtomicType[] { YearMonthDurationType.YEARMONTH_DURATION,
                        NumericType.getInstance() }, YearMonthDurationType.YEARMONTH_DURATION),
                // op:divide-dayTimeDuration(xdt:dayTimeDuration, xs:double) as xdt:dayTimeDuration
                new Pair(new AtomicType[] { DayTimeDurationType.DAYTIME_DURATION,
                        NumericType.getInstance() }, DayTimeDurationType.DAYTIME_DURATION),
                // op:divide-yearMonthDuration-by-yearMonthDuration(xdt:yearMonthDuration, xdt:yearMonthDuration) as xs:decimal
                new Pair(new AtomicType[] { YearMonthDurationType.YEARMONTH_DURATION,
                        YearMonthDurationType.YEARMONTH_DURATION }, DecimalType.DECIMAL),
                // op:divide-dayTimeDuration-by-dayTimeDuration(xdt:dayTimeDuration, xdt:dayTimeDuration) as xs:decimal
                new Pair(new AtomicType[] { DayTimeDurationType.DAYTIME_DURATION,
                        DayTimeDurationType.DAYTIME_DURATION }, DecimalType.DECIMAL),
                // workaround
                new Pair(new AtomicType[] { NumericType.getInstance(), NumericType.getInstance() }, DoubleType.DOUBLE),
                new Pair(new AtomicType[] { UntypedAtomicType.UNTYPED_ATOMIC,
                        NumericType.getInstance() }, DoubleType.DOUBLE),
                new Pair(new AtomicType[] { NumericType.getInstance(),
                        UntypedAtomicType.UNTYPED_ATOMIC }, DoubleType.DOUBLE),
                new Pair(new AtomicType[] { UntypedAtomicType.UNTYPED_ATOMIC,
                        UntypedAtomicType.UNTYPED_ATOMIC }, DoubleType.DOUBLE) };
        return s;
    }

    public InternalFunction staticAnalysis(StaticContext context, Sequence left, Sequence right)
            throws XQueryException {
        final Type[] t = new Type[2];
        t[0] = left.getType();
        t[1] = right.getType();
        return resolve(t);
    }

    public Sequence eval(DynamicContext ctxt, Item... args) throws XQueryException {
        assert (args.length == 2) : args;
        // dispatch exec
        AtomicType retType = getReturnType();
        final Exec exec;
        if(TypeUtil.subtypeOf(retType, DecimalType.DECIMAL)) {
            if(TypeUtil.subtypeOf(args[0].getType(), DurationType.DURATION)
                    || TypeUtil.subtypeOf(args[1].getType(), DurationType.DURATION)) {
                exec = new DivDurationByDuration();
            } else if(TypeUtil.subtypeOf(args[0].getType(), IntegerType.INTEGER)
                    || TypeUtil.subtypeOf(args[1].getType(), IntegerType.INTEGER)) {
                exec = new DivInteger();
            } else {
                exec = new DivDecimal();
            }
        } else if(TypeUtil.subtypeOf(retType, FloatType.FLOAT)) {
            exec = new DivFloat();
        } else if(TypeUtil.subtypeOf(retType, DoubleType.DOUBLE)) {
            if(TypeUtil.subtypeOf(args[0].getType(), DurationType.DURATION)
                    || TypeUtil.subtypeOf(args[1].getType(), DurationType.DURATION)) {
                exec = new DivDurationByDuration();
            } else {
                exec = new DivDouble();
            }
        } else if(TypeUtil.subtypeOf(retType, DurationType.DURATION)) {
            exec = new DivDuration();
        } else {
            throw new IllegalStateException("Unexpected return type: " + retType);
        }
        final AtomicValue ret = exec.eval(ctxt, args[0], args[1]);
        return ret == null ? ValueSequence.EMPTY_SEQUENCE : ret;
    }

    static final class DivInteger extends Exec {
        static final DivInteger INSTANCE = new DivInteger();

        public XDecimal eval(DynamicContext dynEnv, Item v1, Item v2) throws XQueryException {
            BigDecimal res = DivDecimal.compute(v1, v2, dynEnv); // Use DivDecimal to return xs:decimal
            return XDecimal.valueOf(res);
        }

        /**
         * Compute the result without the remainder.
         *
         * @see IdivOp#eval(DynamicContext, Item[])
         */
        public static long compute(final Item v1, final Item v2, final DynamicContext dynEnv)
                throws XQueryException {
            final long divisor = asLong(v2, dynEnv);
            if(divisor == 0) {
                throw new DynamicError("err:FOAR0001", "divide by zero");
            }
            long src = asLong(v1, dynEnv);
            long res = src / divisor;
            return res;
        }
    }

    static final class DivFloat extends Exec {
        static final DivFloat INSTANCE = new DivFloat();

        public XFloat eval(DynamicContext dynEnv, Item v1, Item v2) throws XQueryException {
            float res = compute(v1, v2, dynEnv);
            return XFloat.valueOf(res);
        }

        public static float compute(final Item v1, final Item v2, final DynamicContext dynEnv)
                throws XQueryException {
            final float divisor = asFloat(v2, dynEnv);
            if(divisor == 0) {
                return Float.NaN;
            }
            final float f1 = asFloat(v1, dynEnv);
            // If either operand is NaN or if $arg1 is INF or -INF then an error is raised
            // [err:FOAR0002].
            if(f1 != f1 || Float.isInfinite(f1)) {
                throw new DynamicError("err:FOAR0002", "Invalid $arg1 operand: "
                        + Double.toString(f1));
            }
            if(divisor != divisor) {
                throw new DynamicError("err:FOAR0002", "Invalid $arg2 operand: "
                        + Double.toString(divisor));
            }
            float res = f1 / divisor;
            return res;
        }
    }

    static final class DivDouble extends Exec {
        static final DivDouble INSTANCE = new DivDouble();

        public XDouble eval(DynamicContext dynEnv, Item v1, Item v2) throws XQueryException {
            double res = compute(v1, v2, dynEnv);
            return XDouble.valueOf(res);
        }

        public static double compute(final Item v1, final Item v2, final DynamicContext dynEnv)
                throws XQueryException {
            final double divisor = asDouble(v2, dynEnv);
            if(divisor == 0) {
                return Double.NaN;
            }
            double d1 = asDouble(v1, dynEnv);
            // If either operand is NaN or if $arg1 is INF or -INF then an error is raised
            // [err:FOAR0002].
            if(d1 != d1 || Double.isInfinite(d1)) {
                throw new DynamicError("err:FOAR0002", "Invalid $arg1 operand: "
                        + Double.toString(d1));
            }
            if(divisor != divisor) {
                throw new DynamicError("err:FOAR0002", "Invalid $arg2 operand: "
                        + Double.toString(divisor));
            }
            final double res = d1 / divisor;
            return res;
        }
    }

    static final class DivDecimal extends Exec {
        static final DivDecimal INSTANCE = new DivDecimal();

        public XDecimal eval(DynamicContext dynEnv, Item v1, Item v2) throws XQueryException {
            BigDecimal res = compute(v1, v2, dynEnv);
            return new XDecimal(res);
        }

        public static BigDecimal compute(final Item v1, final Item v2, final DynamicContext dynEnv)
                throws XQueryException {
            final BigDecimal divisor = asDecimal(v2, dynEnv);
            if(divisor.equals(BigDecimal.ZERO)) {
                throw new DynamicError("err:FOAR0001", "divide by zero");
            }
            BigDecimal dv1 = asDecimal(v1, dynEnv);
            BigDecimal res = XDecimal.divide(dv1, divisor);
            return res;
        }
    }

    public static final class DivDuration extends Exec {
        static final DivDuration INSTANCE = new DivDuration();

        public DurationValue eval(DynamicContext dynEnv, Item v1, Item v2) throws XQueryException {
            final DurationValue dur1;
            final double divisor;
            if(v1 instanceof DurationValue) {
                dur1 = (DurationValue) v1;
                divisor = NumericOp.asDouble(v2, dynEnv);
            } else {
                dur1 = (DurationValue) v2;
                divisor = NumericOp.asDouble(v1, dynEnv);
            }
            if(divisor == 0) {
                throw new DynamicError("err:FODT0002", "Overflow in duration arithmetic, divided by zero");
            }
            if(Double.isNaN(divisor)) {
                throw new DynamicError("err:FOCA0005", "$arg2 is NaN");
            }
            double res = 1.0 / divisor;
            DurationValue resDur = dur1.multiply(res);
            return resDur;
        }

    }

    public static final class DivDurationByDuration extends Exec {
        static final DivDurationByDuration INSTANCE = new DivDurationByDuration();

        public XDecimal eval(DynamicContext dynEnv, Item v1, Item v2) throws XQueryException {
            DurationValue d1 = (DurationValue) v1;
            DurationValue d2 = (DurationValue) v2;

            final int dt1 = d1.getDurationType().getTypeId();
            final int dt2 = d2.getDurationType().getTypeId();
            if(dt1 == dt2) {
                if(dt1 == TypeTable.YEAR_MONTH_DURATION_TID) {
                    return evalYearMonthDuration(d1, d2);
                }
                //TODO else if(dt1 == TypeTable.DAYTIME_DURATION_TID) {}
            }

            final double divisor = d2.getTimeInMillis();
            if(divisor == 0) {
                throw new DynamicError("err:FODT0002", "Overflow in duration arithmetic, divided by zero");
            }
            if(Double.isNaN(divisor)) {
                throw new DynamicError("err:FOCA0005", "$arg2 is NaN");
            }
            double l1 = d1.getTimeInMillis();
            double res = l1 / divisor;
            BigDecimal bdv = BigDecimal.valueOf(res);
            return XDecimal.valueOf(bdv);
        }

        private static XDecimal evalYearMonthDuration(final DurationValue d1, final DurationValue d2)
                throws DynamicError {
            final int divisor = d2.totalMonths();
            if(divisor == 0) {
                throw new DynamicError("err:FODT0002", "Overflow in duration arithmetic, divided by zero");
            }
            double m1 = d1.totalMonths();
            double res = m1 / divisor;
            BigDecimal bdv = BigDecimal.valueOf(res);
            return XDecimal.valueOf(bdv);
        }
    }

}
TOP

Related Classes of xbird.xquery.operator.math.DivOp$DivDouble

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.