/** 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; } }
Weight maxValue() const { auto maxval = var()->maxValue(); if(getFixedDiff()>0 && maxval+getFixedDiff()<maxval){ return posInfinity(); } if(getFixedDiff()<0 && maxval-getFixedDiff()<maxval){ return negInfinity(); } return maxval+getFixedDiff(); }
/** Returns the floor of this Numeric */ Numeric::Ptr ATFloatOrDerivedImpl::floor(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: { if (isZero() && isNegative()) return negZero(context); return newFloat(_float.floor(), context); } default: { assert(false); return 0; // should never get here } } }
/** 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 Additive inverse of this Numeric */ Numeric::Ptr ATFloatOrDerivedImpl::invert(const DynamicContext* context) const { switch (_state) { case NaN: return this; case INF: return negInfinity(context); case NEG_INF: return infinity(context); case NEG_NUM: case NUM: if(this->isZero()) { if(this->isNegative()) return newFloat(0, context); else return negZero(context); } return newFloat(_float.neg(), context); default: assert(false); return 0; // should never get here } }
/** 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; } }
/** 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; } }