/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtXmlPatterns module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // /** * @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; const QString qret = qdtoa(m_value, &decimalPoint, &sign); 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; }