/** Returns the mod of its operands as a Numeric */ Numeric::Ptr ATFloatOrDerivedImpl::mod(const Numeric::Ptr &other, const DynamicContext* context) const { if(other->getPrimitiveTypeIndex() == AnyAtomicType::DECIMAL) { // if other is a decimal, promote it to xs:float return this->mod((const Numeric::Ptr )other->castAs(this->getPrimitiveTypeIndex(), context), context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::DOUBLE) { // if other is a double, promote this to xs:double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->mod(other, context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::FLOAT) { // same primitive type, can make comparison const ATFloatOrDerivedImpl* otherImpl = (ATFloatOrDerivedImpl*)(const Numeric*)other; if(this->isNaN() || otherImpl->isNaN() || this->isInfinite() || otherImpl->isZero()) { return notANumber(context); } else if(otherImpl->isInfinite() || this->isZero()) { return (const Numeric::Ptr )this->castAs(AnyAtomicType::FLOAT, context); } else { MAPM result = _float; MAPM r; r = result.integer_divide(otherImpl->_float); result -= r * otherImpl->_float; if (result == 0 && isNegative()) return negZero(context); return newFloat(result, context); } } else { assert(false); // should never get here, numeric types are xs:decimal, xs:float, xs:integer and xs:double return 0; } }
Sequence FunctionRegexGroup::createSequence(DynamicContext *context, int flags) const { XPath2MemoryManager *mm = context->getMemoryManager(); const RegexGroupStore *store = context->getRegexGroupStore(); if(store == 0) return Sequence(context->getItemFactory()->createString(XMLUni::fgZeroLenString, context), mm); Numeric::Ptr indexItem = getParamNumber(1, context)->next(context); if(indexItem->isNegative()) return Sequence(context->getItemFactory()->createString(XMLUni::fgZeroLenString, context), mm); const XMLCh *indexStr = indexItem->asString(context); int index = 0; while(*indexStr != 0) { if(*indexStr >= '0' && *indexStr <= '9') { index *= 10; index += *indexStr - '0'; } ++indexStr; } const XMLCh *result = store->getGroup(index); if(result == 0) result = XMLUni::fgZeroLenString; return Sequence(context->getItemFactory()->createString(result, context), mm); }
TEST_F(TestNumericFactory, GetShouldReturnValidNumericObject) { NumericFactory factory; factory.Add("TEST", createInstance); Numeric::Ptr numeric = factory.Get("TEST", BASE_DECIMAL); EXPECT_NE(static_cast<Numeric*>(0), numeric.get()); }
Item::Ptr PromoteNumericResult::next(DynamicContext *context) { Item::Ptr item = parent_->next(context); if(item.notNull()) { assert(item->isAtomicValue()); const AnyAtomicType *atomic = (const AnyAtomicType *)item.get(); // 3. For each numeric item in the atomic sequence that can be promoted to the expected atomic type using // the promotion rules in B.1 Type Promotion, the promotion is done. if(atomic->isNumericValue()) { try { const Numeric::Ptr promotedType = ((const Numeric*)atomic)-> promoteTypeIfApplicable(typeIndex_, context); if(promotedType.notNull()) { item = promotedType; } } catch (XPath2TypeCastException &e) { XQThrow(XPath2ErrorException, X("SequenceType::AtomicTypeConvertFunctionArgResult::next"), X("Numeric type promotion failed (for promotable type)")); } catch (const XMLException& e) { XQThrow(XPath2ErrorException, X("SequenceType::AtomicTypeConvertFunctionArgResult::next"), X("Numeric type promotion failed (for promotable type)")); } } } else { parent_ = 0; } return item; }
Result FunctionPower::createResult(DynamicContext* context, int flags) const { Numeric::Ptr base = getNumericParam(1, context); if(base.isNull()) return 0; Numeric::Ptr pow = getNumericParam(2, context); if(pow.isNull()) return 0; return (Item::Ptr)base->power(pow, context); }
/** Returns a Numeric object which is the difference of this and * other */ Numeric::Ptr ATFloatOrDerivedImpl::subtract(const Numeric::Ptr &other, const DynamicContext* context) const { if(other->getPrimitiveTypeIndex() == AnyAtomicType::DECIMAL) { // if other is a decimal, promote it to xs:float return this->subtract((const Numeric::Ptr )other->castAs(this->getPrimitiveTypeIndex(), context), context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::DOUBLE) { // if other is a double, promote this to xs:double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->subtract(other, context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::FLOAT) { // same primitive type, can make comparison ATFloatOrDerivedImpl* otherImpl = (ATFloatOrDerivedImpl*)(const Numeric*)other; if(otherImpl->_state == NaN) return notANumber(context); switch (_state) { case NaN: return notANumber(context); case INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case NEG_NUM: case NUM: return infinity(context); // INF - NUM = INF case INF: return notANumber(context); // INF - INF = NaN case NEG_INF: return infinity(context); // INF - (-INF) = INF default: assert(false); return 0; // should never get here } } case NEG_INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); //case taken care of above case NEG_NUM: case NUM: return negInfinity(context); // -INF - NUM = -INF case INF: return negInfinity(context); // -INF - INF = -INF case NEG_INF: return notANumber(context); // -INF - (-INF) = NaN default: assert(false); return 0; // should never get here } } case NEG_NUM: case NUM: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case INF: return negInfinity(context); // NUM - INF = -INF case NEG_INF: return infinity(context); // NUM - (-INF) = INF case NEG_NUM: case NUM: return newFloat(_float - otherImpl->_float, context); default: assert(false); return 0; // should never get here } } default: assert(false); return 0; // should never get here } } else { assert(false); // should never get here, numeric types are xs:decimal, xs:float, xs:integer and xs:double return 0; } }
Sequence FunctionFloor::createSequence(DynamicContext* context, int flags) const { Numeric::Ptr numericArg = getNumericParam(1, context); //If the argument is the empty sequence, the empty sequence is returned. if(numericArg.isNull()) { return Sequence(context->getMemoryManager()); } if(numericArg->isNaN() || numericArg->isInfinite()) return Sequence(numericArg, context->getMemoryManager()); return Sequence(numericArg->floor(context), context->getMemoryManager()); }
Sequence FunctionRound::createSequence(DynamicContext* context, int flags) const { XPath2MemoryManager* memMgr = context->getMemoryManager(); Numeric::Ptr numericArg = getNumericParam(1, context); //If the argument is the empty sequence, the empty sequence is returned. if(numericArg.isNull()) { return Sequence(memMgr); } if(numericArg->isNaN() || numericArg->isInfinite()) return Sequence(numericArg, memMgr); return Sequence(numericArg->round(context), memMgr); }
Item::Ptr nextOrTail(Result &tail, DynamicContext *context) { Numeric::Ptr one = context->getItemFactory()->createDouble(1, context); Result source = ClosureResult::create(_func->getArguments()[0], context); Numeric::Ptr i = one; Numeric::Ptr position = ((Numeric*)_func->getParamNumber(2, context)->next(context).get())->round(context); while(i->lessThan(position, context) && source->next(context).notNull()) { i = i->add(one, context); } tail = source; return 0; }
FTSelection *FTDistance::optimize(FTContext *ftcontext, bool execute) const { XPath2MemoryManager *mm = ftcontext->context->getMemoryManager(); if(execute || range_.arg1->isConstant()) { Result rangeResult = range_.arg1->createResult(ftcontext->context); Numeric::Ptr num = (Numeric::Ptr)rangeResult->next(ftcontext->context); long distance = ::atol(UTF8(num->asString(ftcontext->context))); switch(range_.type) { case FTRange::EXACTLY: { FTSelection *result = new (mm) FTDistanceLiteral(arg_, FTRange::EXACTLY, distance, 0, unit_, mm); result->setLocationInfo(this); return result->optimize(ftcontext, execute); } case FTRange::AT_LEAST: { FTSelection *result = new (mm) FTDistanceLiteral(arg_, FTRange::AT_LEAST, distance, 0, unit_, mm); result->setLocationInfo(this); return result->optimize(ftcontext, execute); } case FTRange::AT_MOST: { FTSelection *result = new (mm) FTDistanceLiteral(arg_, FTRange::AT_MOST, distance, 0, unit_, mm); result->setLocationInfo(this); return result->optimize(ftcontext, execute); } case FTRange::FROM_TO: { Result rangeResult2 = range_.arg2->createResult(ftcontext->context); Numeric::Ptr num2 = (Numeric::Ptr)rangeResult2->next(ftcontext->context); long distance2 = ::atol(UTF8(num->asString(ftcontext->context))); FTSelection *result = new (mm) FTDistanceLiteral(arg_, FTRange::FROM_TO, distance, distance2, unit_, mm); result->setLocationInfo(this); return result->optimize(ftcontext, execute); } } } FTSelection *newarg = arg_->optimize(ftcontext, execute); if(newarg == 0) return 0; if(newarg->getType() == WORD) { return newarg; } newarg = new (mm) FTDistance(range_, unit_, newarg, mm); newarg->setLocationInfo(this); return newarg; }
/** Rounds this Numeric to the given precision, and rounds a half to even */ Numeric::Ptr ATDecimalOrDerivedImpl::roundHalfToEven(const Numeric::Ptr &precision, const DynamicContext* context) const { ATDecimalOrDerived::Ptr decimal_precision = (const Numeric::Ptr)precision->castAs(this->getPrimitiveTypeIndex(), context); MAPM exp = MAPM(10).pow(((ATDecimalOrDerivedImpl*)(const ATDecimalOrDerived*)decimal_precision)->_decimal); MAPM value = _decimal * exp; bool halfVal = false; // check if we're rounding on a half value if((value-0.5) == (value.floor())) { halfVal = true; } value = _decimal * exp + 0.5; value = value.floor(); // if halfVal make sure what we return has the least significant digit even if (halfVal) { if(value.is_odd()) { value = value - 1; } } value = value / exp; // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return context->getItemFactory()->createInteger(value, context); } return context->getItemFactory()->createDecimal(value, context); }
/** Rounds this Numeric to the given precision, and rounds a half to even */ Numeric::Ptr ATFloatOrDerivedImpl::roundHalfToEven(const Numeric::Ptr &precision, const DynamicContext* context) const { switch (_state) { case NaN: return notANumber(context); case INF: return infinity(context); case NEG_INF: return negInfinity(context); case NEG_NUM: case NUM: break; default: { assert(false); return 0; // should never get here } } if (isZero() && isNegative()) return this; ATFloatOrDerived::Ptr float_precision = (const Numeric::Ptr)precision->castAs(this->getPrimitiveTypeIndex(), context); MAPM exp = MAPM(10).pow(((ATFloatOrDerivedImpl*)(const ATFloatOrDerived*)float_precision)->_float); MAPM value = _float * exp; bool halfVal = false; // check if we're rounding on a half value if((value-0.5) == (value.floor())) { halfVal = true; } value = _float * exp + 0.5; value = value.floor(); // if halfVal make sure what we return has the least significant digit even if (halfVal) { if(value.is_odd()) { value = value - 1; } } value = value / exp; // the spec doesn't actually say to do this, but djf believes this is the correct way to handle rounding of -ve values which will result in 0.0E0 // if (value == 0 && isNegative()) // return negZero(context); return newFloat(value, context); }
/** Returns the arithmetic product of its operands as a Numeric */ Numeric::Ptr ATDecimalOrDerivedImpl::mod(const Numeric::Ptr &other, const DynamicContext* context) const { if(this->isOfType(other->getTypeURI(), other->getTypeName(), context)) { // if both are of the same type exactly, we can perform the modulo const ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)(const Numeric*)other; if(otherImpl->isZero()) { XQThrow2(::IllegalArgumentException, X("ATDecimalOrDerivedImpl::mod"), X("Division by zero [err:FOAR0001]")); } MAPM result = _decimal; MAPM r; r = result.integer_divide(otherImpl->_decimal); result -= r * otherImpl->_decimal; // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return context->getItemFactory()->createInteger(result, context); } return context->getItemFactory()->createDecimal(result, context); } else if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->mod(other, context); } else if (this->isInstanceOfType(other->getTypeURI(), other->getTypeName(), context)) { // here we know we have two decimals, and this is 'lower' in the hierarchy than other // so cast this to other's type return ((const Numeric::Ptr )this->castAs(AnyAtomicType::DECIMAL, other->getTypeURI(), other->getTypeName(), context))->mod(other, context); } else if (other->isInstanceOfType(this->getTypeURI(), this->getTypeName(), context)) { // here we have two decimals, and this is 'higher' in the hierarchy than other // so cast other to this' type return this->mod((const Numeric::Ptr )other->castAs(AnyAtomicType::DECIMAL, this->getTypeURI(), this->getTypeName(), context), context); } else { // we have two separate branches. if either is instance of integer, cast it to integer, otherwise, cast to decimal // revisit: this is not the prettiest way to do it. You would want to go up the tree one by one instead of // jumping to integer and decimal ATDecimalOrDerived::Ptr first; ATDecimalOrDerived::Ptr second; if(this->_isInteger) { first = (const ATDecimalOrDerived::Ptr )this->castAs(AnyAtomicType::DECIMAL, SchemaSymbols::fgURI_SCHEMAFORSCHEMA, SchemaSymbols::fgDT_INTEGER, context); } else { first = (const ATDecimalOrDerived::Ptr )this->castAs(AnyAtomicType::DECIMAL, context); } if(((ATDecimalOrDerivedImpl*)(const Numeric*)other)->_isInteger) { second = (const ATDecimalOrDerived::Ptr )other->castAs(AnyAtomicType::DECIMAL, SchemaSymbols::fgURI_SCHEMAFORSCHEMA, SchemaSymbols::fgDT_INTEGER, context); } else { second = (const ATDecimalOrDerived::Ptr )other->castAs(AnyAtomicType::DECIMAL, context); } return first->mod(second, context); } }
/** Returns a Numeric object which is the difference of this and * other */ Numeric::Ptr ATDecimalOrDerivedImpl::subtract(const Numeric::Ptr &other, const DynamicContext* context) const { if(this->isOfType(other->getTypeURI(), other->getTypeName(), context)) { // if both are of the same type exactly, we can perform subtraction ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)(const Numeric*)other; // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return context->getItemFactory()->createInteger(_decimal - otherImpl->_decimal, context); } return context->getItemFactory()->createDecimal(_decimal - otherImpl->_decimal, context); } else if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->subtract(other, context); } else if (this->isInstanceOfType(other->getTypeURI(), other->getTypeName(), context)) { // here we know we have two decimals, and this is 'lower' in the hierarchy than other // so cast this to other's type return ((const Numeric::Ptr )this->castAs(AnyAtomicType::DECIMAL, other->getTypeURI(), other->getTypeName(), context))->subtract(other, context); } else if (other->isInstanceOfType(this->getTypeURI(), this->getTypeName(), context)) { // here we have two decimals, and this is 'higher' in the hierarchy than other // so cast other to this' type return this->subtract((const Numeric::Ptr )other->castAs(AnyAtomicType::DECIMAL, getTypeURI(), getTypeName(), context), context); } else { // we have two separate branches. if either is instance of integer, cast it to integer, otherwise, cast to decimal // revisit: this is not the prettiest way to do it. You would want to go up the tree one by one instead of // jumping to integer and decimal ATDecimalOrDerived::Ptr first; ATDecimalOrDerived::Ptr second; if(this->_isInteger) { first = (const ATDecimalOrDerived::Ptr )this->castAs(AnyAtomicType::DECIMAL, SchemaSymbols::fgURI_SCHEMAFORSCHEMA, SchemaSymbols::fgDT_INTEGER, context); } else { first = (const ATDecimalOrDerived::Ptr )this->castAs(AnyAtomicType::DECIMAL, context); } if(((ATDecimalOrDerivedImpl*)(const Numeric*)other)->_isInteger) { second = (const ATDecimalOrDerived::Ptr )other->castAs(AnyAtomicType::DECIMAL, SchemaSymbols::fgURI_SCHEMAFORSCHEMA, SchemaSymbols::fgDT_INTEGER, context); } else { second = (const ATDecimalOrDerived::Ptr )other->castAs(AnyAtomicType::DECIMAL, context); } return first->subtract(second, context); } }
/** Returns a Numeric object which is the sum of this and other */ Numeric::Ptr ATFloatOrDerivedImpl::add(const Numeric::Ptr &other, const DynamicContext* context) const { if(other->getPrimitiveTypeIndex() == AnyAtomicType::DECIMAL) { // if other is a decimal, promote it to xs:float return this->add((const Numeric::Ptr )other->castAs(this->getPrimitiveTypeIndex(), context), context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::DOUBLE) { // if other is a double, promote this to xs:double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->add(other, context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::FLOAT) { // same primitive type, can make comparison ATFloatOrDerivedImpl* otherImpl = (ATFloatOrDerivedImpl*)(const Numeric*)other; if(otherImpl->_state == NaN) return notANumber(context); switch (_state) { case NaN: return notANumber(context); case INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case NEG_NUM: case NUM: return infinity(context); // INF + NUM = INF case INF: return infinity(context); // INF + INF = INF case NEG_INF: return notANumber(context); // INF + (-INF) = NaN default: assert(false); return 0; // should never get here } } case NEG_INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); //case taken care of above case NEG_NUM: case NUM: return negInfinity(context); // -INF + NUM = -INF case INF: return notANumber(context); // -INF + INF = NaN case NEG_INF: return negInfinity(context); // -INF + (-INF) = -INF default: assert(false); return 0; // should never get here } } case NEG_NUM: case NUM: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case INF: return infinity(context); case NEG_INF: return negInfinity(context); case NEG_NUM: case NUM: { // Handle positive and negative zero if(_float.sign()==0 && otherImpl->_float!=0) return other; else if(_float.sign()!=0 && otherImpl->_float==0) return this; else if(_float.sign()==0 && otherImpl->_float==0) { if(_state==otherImpl->_state) // sum of two zero of the same sign -> result is equal to any of the two items return this; else // sum of two zero of different sign -> result is equal to +0 return newFloat(0, context); } return newFloat(_float + otherImpl->_float, context); } default: assert(false); return 0; // should never get here } } default: assert(false); return 0; // should never get here } } else { assert(false); // should never get here, numeric types are xs:decimal, xs:float, xs:integer and xs:double return 0; } }
Result FunctionAsin::createResult(DynamicContext* context, int flags) const { Numeric::Ptr num = getNumericParam(1, context); if(num.isNull()) return 0; return (Item::Ptr)num->asin(context); }
/** Returns a Numeric object which is the quotient of this and other */ Numeric::Ptr ATFloatOrDerivedImpl::divide(const Numeric::Ptr &other, const DynamicContext* context) const { if(other->getPrimitiveTypeIndex() == AnyAtomicType::DECIMAL) { // if other is a decimal, promote it to xs:float return this->divide((const Numeric::Ptr )other->castAs(this->getPrimitiveTypeIndex(), context), context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::DOUBLE) { // if other is a double, promote this to xs:double return ((const Numeric::Ptr )this->castAs(other->getPrimitiveTypeIndex(), context))->divide(other, context); } else if (other->getPrimitiveTypeIndex() == AnyAtomicType::FLOAT) { // same primitive type, can make comparison ATFloatOrDerivedImpl* otherImpl = (ATFloatOrDerivedImpl*)(const Numeric*)other; if(otherImpl->_state == NaN) return notANumber(context); switch (_state) { case NaN: return notANumber(context); case INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case NEG_NUM: case NUM: return other->isPositive() ? infinity(context) : negInfinity(context); // INF / NUM = +/-INF case INF: return notANumber(context); // INF / INF = NaN case NEG_INF: return notANumber(context); // INF / (-INF) = NaN default: assert(false); return 0; // should never get here } // switch }// case case NEG_INF: { switch(otherImpl->_state) { case NaN: return notANumber(context); //case taken care of above case NEG_NUM: case NUM: return other->isPositive() ? negInfinity(context) : infinity(context); // -INF / NUM = -INF case INF: return notANumber(context); // -INF / INF = NaN case NEG_INF: return notANumber(context); // -INF / (-INF) = NaN default: assert(false); return 0; // should never get here } // switch } // case case NEG_NUM: case NUM: { switch(otherImpl->_state) { case NaN: return notANumber(context); // case taken care of above case INF: { // NUM / INF = +/-0 if(this->isNegative()) { return negZero(context); } else { return newFloat(0, context); } }// case case NEG_INF: { // NUM / -INF = +/-0 if(this->isPositive()) { return negZero(context); } else { return newFloat(0, context); } }// case case NEG_NUM: case NUM: { if(other->isZero()) { if(this->isZero()) return notANumber(context); if((this->isNegative() && other->isPositive()) || (this->isPositive() && other->isNegative())) { return negInfinity(context); // NUM / (-0) or (-NUM) / 0 = -INF } else { return infinity(context); // NUM / 0 or (-NUM) / (-0) = INF } } else if(this->isZero()) { if((this->isNegative() && other->isPositive()) || (this->isPositive() && other->isNegative())) { return negZero(context); // 0 / (-NUM) or (-0) / NUM = -0 } else { return newFloat(0, context); // 0 / NUM or (-0) / (-NUM) = 0 } } return newFloat(_float / otherImpl->_float, context); }// case default: assert(false); return 0; // should never get here }// switch }// case default: assert(false); return 0; // should never get here }// switch } else { assert(false); // should never get here, numeric types are xs:decimal, xs:float, xs:integer and xs:double return 0; } }
Numeric::Ptr ATFloatOrDerivedImpl::power(const Numeric::Ptr &other, const DynamicContext* context) const { switch(other->getPrimitiveTypeIndex()) { case DECIMAL: // if other is a decimal, promote it to xs:float return power(context->getItemFactory()->createFloat(other->asMAPM(), context), context); case FLOAT: { ATFloatOrDerivedImpl *otherImpl = (ATFloatOrDerivedImpl*)other.get(); switch(_state) { case NaN: return this; case INF: { switch(otherImpl->_state) { case NaN: return other; case NEG_NUM: case NUM: case INF: case NEG_INF: return this; default: assert(false); return 0; // should never get here } } case NEG_INF: { switch(otherImpl->_state) { case NaN: return other; case NEG_NUM: case NUM: case INF: case NEG_INF: return this; default: assert(false); return 0; // should never get here } } case NEG_NUM: case NUM: { switch(otherImpl->_state) { case NaN: return other; case INF: return other; case NEG_INF: return infinity(context); case NEG_NUM: case NUM: return newFloat(_float.pow(otherImpl->_float), context); default: assert(false); return 0; // should never get here } } default: assert(false); return 0; // should never get here } } case DOUBLE: return ((Numeric*)this->castAs(DOUBLE, context).get())->power(other, context); default: assert(false); return 0; // Shouldn't happen } }