| /******************************************************************************* |
| * Copyright (c) 2005, 2009 Andrea Bittau, University College London, and others |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Andrea Bittau - initial API and implementation from the PsychoPath XPath 2.0 |
| * Mukul Gandhi - bug 274805 - improvements to xs:integer data type |
| * Mukul Gandhi - bug 279406 - improvements to negative zero values for xs:float |
| * David Carver - bug 262765 - fixed rounding errors. |
| * David Carver - bug 282223 - fixed casting errors. |
| * Jesper Steen Moller - Bug 286062 - Fix idiv error cases and increase precision |
| * Jesper Steen Moller - bug 281028 - Added constructor from string |
| *******************************************************************************/ |
| |
| package org.eclipse.wst.xml.xpath2.processor.internal.types; |
| |
| import java.math.BigDecimal; |
| import java.math.RoundingMode; |
| import java.util.Iterator; |
| |
| import org.eclipse.wst.xml.xpath2.processor.DynamicContext; |
| import org.eclipse.wst.xml.xpath2.processor.DynamicError; |
| import org.eclipse.wst.xml.xpath2.processor.ResultSequence; |
| import org.eclipse.wst.xml.xpath2.processor.ResultSequenceFactory; |
| |
| /** |
| * A representation of the Float datatype |
| */ |
| public class XSFloat extends NumericType { |
| |
| private static final String XS_FLOAT = "xs:float"; |
| private Float _value; |
| private XPathDecimalFormat format = new XPathDecimalFormat("0.#######E0"); |
| /** |
| * Initiates a representation of the supplied number |
| * |
| * @param x |
| * The number to be stored |
| */ |
| public XSFloat(float x) { |
| _value = x; |
| } |
| |
| /** |
| * Initiates a representation of 0 |
| */ |
| public XSFloat() { |
| this(0); |
| } |
| |
| /** |
| * Initialises using a String represented number |
| * |
| * @param init |
| * String representation of the number to be stored |
| */ |
| public XSFloat(String init) throws DynamicError { |
| try { |
| if (init.equals("-INF")) { |
| _value = Float.NEGATIVE_INFINITY; |
| } else if (init.equals("INF")) { |
| _value = Float.POSITIVE_INFINITY; |
| } else { |
| _value = new Float(init); |
| } |
| } catch (NumberFormatException e) { |
| throw DynamicError.cant_cast(null); |
| } |
| } |
| /** |
| * Retrieves the datatype's full pathname |
| * |
| * @return "xs:float" which is the datatype's full pathname |
| */ |
| @Override |
| public String string_type() { |
| return XS_FLOAT; |
| } |
| |
| /** |
| * Retrieves the datatype's name |
| * |
| * @return "float" which is the datatype's name |
| */ |
| @Override |
| public String type_name() { |
| return "float"; |
| } |
| |
| /** |
| * Retrieves a String representation of the stored number |
| * |
| * @return String representation of the stored number |
| */ |
| @Override |
| public String string_value() { |
| if (zero()) { |
| return "0"; |
| } |
| if (negativeZero()) { |
| return "-0"; |
| } |
| |
| if (nan()) { |
| return "NaN"; |
| } |
| |
| return format.xpathFormat(_value); |
| } |
| |
| /** |
| * Check for whether this datatype represents NaN |
| * |
| * @return True is this datatype represents NaN. False otherwise |
| */ |
| public boolean nan() { |
| return Float.isNaN(_value); |
| } |
| |
| /** |
| * Check for whether this datatype represents negative or positive infinity |
| * |
| * @return True is this datatype represents infinity. False otherwise |
| */ |
| public boolean infinite() { |
| return Float.isInfinite(_value); |
| } |
| |
| /** |
| * Check for whether this datatype represents 0 |
| * |
| * @return True if this datatype represents 0. False otherwise |
| */ |
| @Override |
| public boolean zero() { |
| return (Float.compare(_value, 0) == 0); |
| } |
| |
| /* |
| * Check for whether this XSFloat represents -0 |
| * |
| * @return True if this XSFloat represents -0. False otherwise. |
| * @since 1.1 |
| */ |
| public boolean negativeZero() { |
| return (Float.compare(_value, -0.0f) == 0); |
| } |
| |
| /** |
| * Creates a new ResultSequence consisting of the retrievable float in the |
| * supplied ResultSequence |
| * |
| * @param arg |
| * The ResultSequence from which to extract the float |
| * @return New ResultSequence consisting of the float supplied |
| * @throws DynamicError |
| */ |
| @Override |
| public ResultSequence constructor(ResultSequence arg) throws DynamicError { |
| ResultSequence rs = ResultSequenceFactory.create_new(); |
| |
| if (arg.empty()) |
| return rs; |
| |
| AnyType aat = arg.first(); |
| |
| if (aat instanceof XSDuration || aat instanceof CalendarType || |
| aat instanceof XSBase64Binary || aat instanceof XSHexBinary || |
| aat instanceof XSAnyURI) { |
| throw DynamicError.invalidType(); |
| } |
| |
| if (!(aat.string_type().equals("xs:string") || aat instanceof NodeType || |
| aat.string_type().equals("xs:untypedAtomic") || |
| aat.string_type().equals("xs:boolean") || |
| aat instanceof NumericType)) { |
| throw DynamicError.cant_cast(null); |
| } |
| |
| |
| try { |
| Float f = null; |
| if (aat.string_value().equals("INF")) { |
| f = Float.POSITIVE_INFINITY; |
| } else if (aat.string_value().equals("-INF")) { |
| f = Float.NEGATIVE_INFINITY; |
| } else if (aat instanceof XSBoolean) { |
| if (aat.string_value().equals("true")) { |
| f = new Float("1.0E0"); |
| } else { |
| f = new Float("0.0E0"); |
| } |
| } else { |
| f = new Float(aat.string_value()); |
| } |
| rs.add(new XSFloat(f.floatValue())); |
| return rs; |
| } catch (NumberFormatException e) { |
| throw DynamicError.cant_cast(null); |
| } |
| |
| } |
| |
| /** |
| * Retrieves the actual float value stored |
| * |
| * @return The actual float value stored |
| */ |
| public float float_value() { |
| return _value; |
| } |
| |
| /** |
| * Equality comparison between this number and the supplied representation. |
| * @param aa |
| * The datatype to compare with |
| * |
| * @return True if the two representations are of the same number. False |
| * otherwise |
| * @throws DynamicError |
| */ |
| public boolean eq(AnyType aa, DynamicContext context) throws DynamicError { |
| AnyType carg = convertArg(aa); |
| if (!(carg instanceof XSFloat)) |
| DynamicError.throw_type_error(); |
| |
| XSFloat f = (XSFloat) carg; |
| if (nan() && f.nan()) { |
| return false; |
| } |
| |
| Float thatvalue = new Float(f.float_value()); |
| Float thisvalue = new Float(float_value()); |
| |
| return thisvalue.equals(thatvalue); |
| } |
| |
| /** |
| * Comparison between this number and the supplied representation. |
| * |
| * @param arg |
| * The datatype to compare with |
| * @return True if the supplied representation is a smaller number than the |
| * one stored. False otherwise |
| * @throws DynamicError |
| */ |
| public boolean gt(AnyType arg, DynamicContext context) throws DynamicError { |
| AnyType carg = convertArg(arg); |
| XSFloat val = (XSFloat) get_single_type(carg, XSFloat.class); |
| return float_value() > val.float_value(); |
| } |
| |
| /** |
| * Comparison between this number and the supplied representation. |
| * |
| * @param arg |
| * The datatype to compare with |
| * @return True if the supplied representation is a greater number than the |
| * one stored. False otherwise |
| * @throws DynamicError |
| */ |
| public boolean lt(AnyType arg, DynamicContext context) throws DynamicError { |
| AnyType carg = convertArg(arg); |
| XSFloat val = (XSFloat) get_single_type(carg, XSFloat.class); |
| return float_value() < val.float_value(); |
| } |
| |
| /** |
| * Mathematical addition operator between this XSFloat and the supplied |
| * ResultSequence. |
| * |
| * @param arg |
| * The ResultSequence to perform an addition with |
| * @return A XSFloat consisting of the result of the mathematical addition. |
| */ |
| public ResultSequence plus(ResultSequence arg) throws DynamicError { |
| ResultSequence carg = convertResultSequence(arg); |
| AnyType at = get_single_arg(carg); |
| if (!(at instanceof XSFloat)) |
| DynamicError.throw_type_error(); |
| XSFloat val = (XSFloat) at; |
| |
| return ResultSequenceFactory.create_new(new XSFloat(float_value() |
| + val.float_value())); |
| } |
| |
| /** |
| * Mathematical subtraction operator between this XSFloat and the supplied |
| * ResultSequence. |
| * |
| * @param arg |
| * The ResultSequence to perform a subtraction with |
| * @return A XSFloat consisting of the result of the mathematical |
| * subtraction. |
| */ |
| public ResultSequence minus(ResultSequence arg) throws DynamicError { |
| ResultSequence carg = constructor(arg); |
| AnyType at = get_single_arg(carg); |
| if (!(at instanceof XSFloat)) |
| DynamicError.throw_type_error(); |
| XSFloat val = (XSFloat) at; |
| |
| return ResultSequenceFactory.create_new(new XSFloat(float_value() |
| - val.float_value())); |
| } |
| |
| /** |
| * Mathematical multiplication operator between this XSFloat and the |
| * supplied ResultSequence. |
| * |
| * @param arg |
| * The ResultSequence to perform a multiplication with |
| * @return A XSFloat consisting of the result of the mathematical |
| * multiplication. |
| */ |
| public ResultSequence times(ResultSequence arg) throws DynamicError { |
| ResultSequence carg = constructor(arg); |
| XSFloat val = (XSFloat) get_single_type(carg, XSFloat.class); |
| return ResultSequenceFactory.create_new(new XSFloat(float_value() |
| * val.float_value())); |
| } |
| |
| /** |
| * Mathematical division operator between this XSFloat and the supplied |
| * ResultSequence. |
| * |
| * @param arg |
| * The ResultSequence to perform a division with |
| * @return A XSFloat consisting of the result of the mathematical division. |
| */ |
| public ResultSequence div(ResultSequence arg) throws DynamicError { |
| ResultSequence carg = convertResultSequence(arg); |
| XSFloat val = (XSFloat) get_single_type(carg, XSFloat.class); |
| return ResultSequenceFactory.create_new(new XSFloat(float_value() |
| / val.float_value())); |
| } |
| |
| /** |
| * Mathematical integer division operator between this XSFloat and the |
| * supplied ResultSequence. |
| * |
| * @param arg |
| * The ResultSequence to perform an integer division with |
| * @return A XSInteger consisting of the result of the mathematical integer |
| * division. |
| */ |
| public ResultSequence idiv(ResultSequence arg) throws DynamicError { |
| ResultSequence carg = convertResultSequence(arg); |
| XSFloat val = (XSFloat) get_single_type(carg, XSFloat.class); |
| |
| if (this.nan() || val.nan()) |
| throw DynamicError.numeric_overflow("Dividend or divisor is NaN"); |
| |
| if (this.infinite()) |
| throw DynamicError.numeric_overflow("Dividend is infinite"); |
| |
| if (val.zero()) |
| throw DynamicError.div_zero(null); |
| |
| BigDecimal result = BigDecimal.valueOf((float_value() / val.float_value())); |
| return ResultSequenceFactory.create_new(new XSInteger(result.toBigInteger())); |
| } |
| |
| /** |
| * Mathematical modulus operator between this XSFloat and the supplied |
| * ResultSequence. Due to no numeric type promotion or conversion, the |
| * ResultSequence must be of type XSFloat. |
| * |
| * @param arg |
| * The ResultSequence to perform a modulus with |
| * @return A XSFloat consisting of the result of the mathematical modulus. |
| */ |
| public ResultSequence mod(ResultSequence arg) throws DynamicError { |
| ResultSequence carg = convertResultSequence(arg); |
| XSFloat val = (XSFloat) get_single_type(carg, XSFloat.class); |
| return ResultSequenceFactory.create_new(new XSFloat(float_value() |
| % val.float_value())); |
| } |
| |
| /** |
| * Negates the number stored |
| * |
| * @return A XSFloat representing the negation of the number stored |
| */ |
| @Override |
| public ResultSequence unary_minus() { |
| return ResultSequenceFactory |
| .create_new(new XSFloat(-1 * float_value())); |
| } |
| |
| /** |
| * Absolutes the number stored |
| * |
| * @return A XSFloat representing the absolute value of the number stored |
| */ |
| @Override |
| public NumericType abs() { |
| return new XSFloat(Math.abs(float_value())); |
| } |
| |
| /** |
| * Returns the smallest integer greater than the number stored |
| * |
| * @return A XSFloat representing the smallest integer greater than the |
| * number stored |
| */ |
| @Override |
| public NumericType ceiling() { |
| return new XSFloat((float) Math.ceil(float_value())); |
| } |
| |
| /** |
| * Returns the largest integer smaller than the number stored |
| * |
| * @return A XSFloat representing the largest integer smaller than the |
| * number stored |
| */ |
| @Override |
| public NumericType floor() { |
| return new XSFloat((float) Math.floor(float_value())); |
| } |
| |
| /** |
| * Returns the closest integer of the number stored. |
| * |
| * @return A XSFloat representing the closest long of the number stored. |
| */ |
| @Override |
| public NumericType round() { |
| BigDecimal value = new BigDecimal(float_value()); |
| BigDecimal round = value.setScale(0, RoundingMode.HALF_UP); |
| return new XSFloat(round.floatValue()); |
| } |
| |
| /** |
| * Returns the closest integer of the number stored. |
| * |
| * @return A XSFloat representing the closest long of the number stored. |
| */ |
| @Override |
| public NumericType round_half_to_even() { |
| return round_half_to_even(0); |
| } |
| |
| /** |
| * Returns the closest integer of the number stored with the specified precision. |
| * |
| * @param precision An integer precision |
| * @return A XSFloat representing the closest long of the number stored. |
| */ |
| |
| @Override |
| public NumericType round_half_to_even(int precision) { |
| BigDecimal value = new BigDecimal(_value); |
| BigDecimal round = value.setScale(precision, RoundingMode.HALF_EVEN); |
| return new XSFloat(round.floatValue()); |
| } |
| |
| protected AnyType convertArg(AnyType arg) throws DynamicError { |
| ResultSequence rs = ResultSequenceFactory.create_new(arg); |
| rs = constructor(rs); |
| AnyType carg = rs.first(); |
| return carg; |
| } |
| |
| private ResultSequence convertResultSequence(ResultSequence arg) |
| throws DynamicError { |
| ResultSequence carg = arg; |
| Iterator it = carg.iterator(); |
| while (it.hasNext()) { |
| AnyType type = (AnyType) it.next(); |
| if (type.string_type().equals("xs:untypedAtomic") || |
| type.string_type().equals("xs:string")) { |
| throw DynamicError.throw_type_error(); |
| } |
| } |
| |
| carg = constructor(carg); |
| return carg; |
| } |
| |
| } |