/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** ** This file is part of the QtXmlPatterns module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /** * @file * @short This file is included by qabstractfloat_p.h. * If you need includes in this file, put them in qabstractfloat_p.h, outside of the namespace. */ template AbstractFloat::AbstractFloat(const xsDouble num) : m_value(num) { } template Numeric::Ptr AbstractFloat::fromValue(const xsDouble num) { return Numeric::Ptr(new AbstractFloat(num)); } template AtomicValue::Ptr AbstractFloat::fromLexical(const QString &strNumeric) { /* QString::toDouble() handles the whitespace facet. */ if(strNumeric == QLatin1String("NaN")) return isDouble ? CommonValues::DoubleNaN : CommonValues::FloatNaN; else if(strNumeric == QLatin1String("-INF")) return isDouble ? CommonValues::NegativeInfDouble : CommonValues::NegativeInfFloat; else if(strNumeric == QLatin1String("INF")) return isDouble ? CommonValues::InfDouble : CommonValues::InfFloat; /* QString::toDouble() supports any case as well as +INF, but we don't. */ const QString toUpper(strNumeric.toUpper()); if(toUpper == QLatin1String("-INF") || toUpper == QLatin1String("INF") || toUpper == QLatin1String("+INF") || toUpper == QLatin1String("NAN")) { return ValidationError::createError(); } bool conversionOk = false; const xsDouble num = strNumeric.toDouble(&conversionOk); if(conversionOk) return AtomicValue::Ptr(new AbstractFloat(num)); else return ValidationError::createError(); } template int AbstractFloat::internalSignbit(const xsDouble num) { Q_ASSERT_X(sizeof(xsDouble) == 8 || sizeof(xsDouble) == 4, Q_FUNC_INFO, "This implementation of signbit assumes xsDouble, that is qreal, is 64 bits large."); union { xsDouble asDouble; qint64 asInt; } value; value.asDouble = num; /* The highest bit, the 64'th for those who have 64bit floats, is the sign bit. So we pull it down until that bit is the * only one left. */ if(sizeof(xsDouble) == 8) return value.asInt >> 63; else return value.asInt >> 31; } template bool AbstractFloat::isEqual(const xsDouble a, const xsDouble b) { if(qIsInf(a)) return qIsInf(b) && internalSignbit(a) == internalSignbit(b); else if(qIsInf(b)) return qIsInf(a) && internalSignbit(a) == internalSignbit(b); else { /* Preferably, we would use std::numeric_limits::espilon(), but * we cannot since we cannot depend on the STL. The small xs:double value below, * was extracted by printing the std::numeric_limits::epsilon() using * gdb. */ return qAbs(a - b) <= 2.2204460492503131e-16 * qAbs(a); } } template bool AbstractFloat::isZero() const { return AbstractFloat::isEqual(m_value, 0.0); } template bool AbstractFloat::evaluateEBV(const QExplicitlySharedDataPointer &) const { if(isZero() || qIsNaN(m_value)) return false; else return true; } template QString AbstractFloat::stringValue() const { if(qIsNaN(m_value)) return QLatin1String("NaN"); else if(qIsInf(m_value)) return internalSignbit(m_value) == 0 ? QLatin1String("INF") : QLatin1String("-INF"); /* * If SV has an absolute value that is greater than or equal to 0.000001 * (one millionth) and less than 1000000 (one million), * then the value is converted to an xs:decimal and the resulting xs:decimal * is converted to an xs:string according to the rules above. */ else if(0.000001 <= qAbs(m_value) && qAbs(m_value) < 1000000.0) return Decimal::toString(toDecimal()); /* * If SV has the value positive or negative zero, TV is "0" or "-0" respectively. */ else if(isZero()) return internalSignbit(m_value) == 0 ? QLatin1String("0") : QLatin1String("-0"); else { /* * Besides these special values, the general form of the canonical form for * xs:float and xs:double is a mantissa, which is a xs:decimal, followed by * the letter "E", followed by an exponent which is an xs:integer. */ int sign; int decimalPoint; char *result = 0; static_cast(qdtoa(m_value, -1, 0, &decimalPoint, &sign, 0, &result)); /* If the copy constructor is used instead of QString::operator=(), * it doesn't compile. I have no idea why. */ const QString qret(QString::fromLatin1(result)); /* We use free() instead of delete here, because qlocale.cpp use malloc(). Spotted * by valgrind. */ free(result); QString valueAsString; if(sign) valueAsString += QLatin1Char('-'); valueAsString += qret.at(0); valueAsString += QLatin1Char('.'); if(1 == qret.size()) valueAsString += QLatin1Char('0'); else valueAsString += qret.mid(1); valueAsString += QLatin1Char('E'); decimalPoint--; valueAsString += QString::number(decimalPoint); return valueAsString; } } template xsDouble AbstractFloat::toDouble() const { return m_value; } template xsInteger AbstractFloat::toInteger() const { return static_cast(m_value); } template xsFloat AbstractFloat::toFloat() const { /* No cast, since xsFloat and xsDouble are typedef'ed with the same type. */ return m_value; } template xsDecimal AbstractFloat::toDecimal() const { return static_cast(m_value); } template Numeric::Ptr AbstractFloat::round() const { return AbstractFloat::fromValue(static_cast(roundFloat(m_value))); } template Numeric::Ptr AbstractFloat::roundHalfToEven(const xsInteger precision) const { if(isNaN() || isInf() || isZero()) return Numeric::Ptr(const_cast *>(this)); else { /* The cast to double helps finding the correct pow() version on irix-cc. */ const xsDouble powered = pow(double(10), double(precision)); xsDouble val = powered * m_value; bool isHalf = false; if(val - 0.5 == ::floor(val)) isHalf = true; val = m_value * powered + 0.5; val = ::floor(val); if(isHalf /*&& isOdd(val) or? TODO */) val -= 1; val /= powered; return fromValue(val); } } template Numeric::Ptr AbstractFloat::floor() const { return AbstractFloat::fromValue(static_cast(::floor(m_value))); } template Numeric::Ptr AbstractFloat::ceiling() const { return AbstractFloat::fromValue(static_cast(ceil(m_value))); } template Numeric::Ptr AbstractFloat::abs() const { /* We must use fabs() instead of qAbs() because qAbs() * doesn't return 0 for -0.0. */ return AbstractFloat::fromValue(static_cast(fabs(m_value))); } template bool AbstractFloat::isNaN() const { return qIsNaN(m_value); } template bool AbstractFloat::isInf() const { return qIsInf(m_value); } template ItemType::Ptr AbstractFloat::type() const { return isDouble ? BuiltinTypes::xsDouble : BuiltinTypes::xsFloat; } template Item AbstractFloat::toNegated() const { return fromValue(-m_value).data(); } template bool AbstractFloat::isSigned() const { Q_ASSERT_X(false, Q_FUNC_INFO, "It makes no sense to call this function, see Numeric::isSigned()."); return false; } template qulonglong AbstractFloat::toUnsignedInteger() const { Q_ASSERT_X(false, Q_FUNC_INFO, "It makes no sense to call this function, see Numeric::toUnsignedInteger()."); return 0; }