13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program Tester Core
33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * ----------------------------------------
43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project
63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License");
83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License.
93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at
103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *      http://www.apache.org/licenses/LICENSE-2.0
123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software
143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS,
153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and
173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License.
183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*!
203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file
213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Adjustable-precision floating point operations.
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuFloatFormat.hpp"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMath.h"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deUniquePtr.hpp"
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <sstream>
303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <iomanip>
313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <limits>
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace tcu
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
353c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
383c827367444ee418f129b2c238299f49d3264554Jarkko PoyryInterval chooseInterval(YesNoMaybe choice, const Interval& no, const Interval& yes)
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	switch (choice)
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case NO:	return no;
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case YES:	return yes;
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		case MAYBE:	return no | yes;
451cc61b7d03cad727bbddd00cea8d78f4f6cc9047Jarkko Pöyry		default:	DE_FATAL("Impossible case");
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return Interval();
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyrydouble computeMaxValue (int maxExp, int fractionBits)
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return (deLdExp(1.0, maxExp) +
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			deLdExp(double((1ull << fractionBits) - 1), maxExp - fractionBits));
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // anonymous
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
593c827367444ee418f129b2c238299f49d3264554Jarkko PoyryFloatFormat::FloatFormat (int			minExp,
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						  int			maxExp,
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						  int			fractionBits,
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						  bool			exactPrecision,
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						  YesNoMaybe	hasSubnormal_,
644fdcdd50d72a1317dbab9f75738e5bb9ccd30634Pyry Haulos						  YesNoMaybe	hasInf_,
654fdcdd50d72a1317dbab9f75738e5bb9ccd30634Pyry Haulos						  YesNoMaybe	hasNaN_)
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: m_minExp			(minExp)
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_maxExp			(maxExp)
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_fractionBits	(fractionBits)
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_hasSubnormal	(hasSubnormal_)
704fdcdd50d72a1317dbab9f75738e5bb9ccd30634Pyry Haulos	, m_hasInf			(hasInf_)
714fdcdd50d72a1317dbab9f75738e5bb9ccd30634Pyry Haulos	, m_hasNaN			(hasNaN_)
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_exactPrecision	(exactPrecision)
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_maxValue		(computeMaxValue(maxExp, fractionBits))
743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(minExp <= maxExp);
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * On the definition of ULP
803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * The GLSL spec does not define ULP. However, it refers to IEEE 754, which
823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * (reportedly) uses Harrison's definition:
833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * ULP(x) is the distance between the closest floating point numbers
853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * a and be such that a <= x <= b and a != b
863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Note that this means that when x = 2^n, ULP(x) = 2^(n-p-1), i.e. it is the
883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distance to the next lowest float, not next highest.
893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Furthermore, it is assumed that ULP is calculated relative to the exact
913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * value, not the approximation. This is because otherwise a less accurate
923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * approximation could be closer in ULPs, because its ULPs are bigger.
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * For details, see "On the definition of ulp(x)" by Jean-Michel Muller
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *-----------------------------------------------------------------------*/
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyrydouble FloatFormat::ulp (double x, double count) const
993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int				exp		= 0;
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const double	frac	= deFractExp(deAbs(x), &exp);
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (deIsNaN(frac))
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return TCU_NAN;
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (deIsInf(frac))
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return deLdExp(1.0, m_maxExp - m_fractionBits);
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (frac == 1.0)
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Harrison's ULP: choose distance to closest (i.e. next lower) at binade
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// boundary.
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		--exp;
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (frac == 0.0)
1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		exp = m_minExp;
1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// ULP cannot be lower than the smallest quantum.
1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	exp = de::max(exp, m_minExp);
1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const double		oneULP	= deLdExp(1.0, exp - m_fractionBits);
1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		ScopedRoundingMode	ctx		(DE_ROUNDINGMODE_TO_POSITIVE_INF);
1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return oneULP * count;
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Return the difference between the given nominal exponent and
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! the exponent of the lowest significand bit of the
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! representation of a number with this format.
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! For normal numbers this is the number of significand bits, but
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! for subnormals it is less and for values of exp where 2^exp is too
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! small to represent it is <0
1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyryint FloatFormat::exponentShift (int exp) const
1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return m_fractionBits - de::max(m_minExp - exp, 0);
1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Return the number closest to `d` that is exactly representable with the
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! significand bits and minimum exponent of the floatformat. Round up if
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! `upward` is true, otherwise down.
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyrydouble FloatFormat::round (double d, bool upward) const
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int				exp			= 0;
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const double	frac		= deFractExp(d, &exp);
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		shift		= exponentShift(exp);
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const double	shiftFrac	= deLdExp(frac, shift);
1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const double	roundFrac	= upward ? deCeil(shiftFrac) : deFloor(shiftFrac);
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return deLdExp(roundFrac, exp - shift);
1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Return the range of numbers that `d` might be converted to in the
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! floatformat, given its limitations with infinities, subnormals and maximum
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! exponent.
1553c827367444ee418f129b2c238299f49d3264554Jarkko PoyryInterval FloatFormat::clampValue (double d) const
1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const double	rSign		= deSign(d);
1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int				rExp		= 0;
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!deIsNaN(d));
1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	deFractExp(d, &rExp);
1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (rExp < m_minExp)
1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return chooseInterval(m_hasSubnormal, rSign * 0.0, d);
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (deIsInf(d) || rExp > m_maxExp)
1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return chooseInterval(m_hasInf, rSign * getMaxValue(), rSign * TCU_INFINITY);
1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return Interval(d);
1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! Return the range of numbers that might be used with this format to
1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//! represent a number within `x`.
1733c827367444ee418f129b2c238299f49d3264554Jarkko PoyryInterval FloatFormat::convert (const Interval& x) const
1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	Interval ret;
1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	Interval tmp = x;
1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (x.hasNaN())
1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If NaN might be supported, NaN is a legal return value
1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_hasNaN != NO)
1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			ret |= TCU_NAN;
1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If NaN might not be supported, any (non-NaN) value is legal,
1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// _subject_ to clamping. Hence we modify tmp, not ret.
1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (m_hasNaN != YES)
1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			tmp = Interval::unbounded();
1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Round both bounds _inwards_ to closest representable values.
1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!tmp.empty())
1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		ret |= clampValue(round(tmp.lo(), true)) | clampValue(round(tmp.hi(), false));
1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// If this format's precision is not exact, the (possibly out-of-bounds)
1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// original value is also a possible result.
1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!m_exactPrecision)
1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		ret |= x;
1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return ret;
2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2022e751e3e77060f699c560104e82379d3ce54f67aPyry Haulosdouble FloatFormat::roundOut (double d, bool upward, bool roundUnderOverflow) const
2032e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos{
2042e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos	int	exp	= 0;
2052e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos	deFractExp(d, &exp);
2062e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos
2072e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos	if (roundUnderOverflow && exp > m_maxExp && (upward == (d < 0.0)))
2082e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos		return deSign(d) * getMaxValue();
2092e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos	else
2102e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos		return round(d, upward);
2112e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos}
2122e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos
2132e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos//! Round output of an operation.
2142e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos//! \param roundUnderOverflow Can +/-inf rounded to min/max representable;
2152e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos//!							  should be false if any of operands was inf, true otherwise.
2162e751e3e77060f699c560104e82379d3ce54f67aPyry HaulosInterval FloatFormat::roundOut (const Interval& x, bool roundUnderOverflow) const
2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	Interval ret = x.nan();
2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!x.empty())
2212e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos		ret |= Interval(roundOut(x.lo(), false, roundUnderOverflow),
2222e751e3e77060f699c560104e82379d3ce54f67aPyry Haulos						roundOut(x.hi(), true, roundUnderOverflow));
2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return ret;
2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystd::string	FloatFormat::floatToHex	(double x) const
2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (deIsNaN(x))
2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return "NaN";
2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (deIsInf(x))
2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return (x < 0.0 ? "-" : "+") + std::string("inf");
2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (x == 0.0) // \todo [2014-03-27 lauri] Negative zero
2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return "0.0";
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int					exp			= 0;
2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const double		frac		= deFractExp(deAbs(x), &exp);
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			shift		= exponentShift(exp);
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64		bits		= deUint64(deLdExp(frac, shift));
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64		whole		= bits >> m_fractionBits;
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64		fraction	= bits & ((deUint64(1) << m_fractionBits) - 1);
2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			exponent	= exp + m_fractionBits - shift;
2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int			numDigits	= (m_fractionBits + 3) / 4;
2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint64		aligned		= fraction << (numDigits * 4 - m_fractionBits);
2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream	oss;
2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	oss << (x < 0 ? "-" : "")
2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "0x" << whole << "."
2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< std::hex << std::setw(numDigits) << std::setfill('0') << aligned
2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		<< "p" << std::dec << std::setw(0) << exponent;
2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return oss.str();
2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystd::string FloatFormat::intervalToHex (const Interval& interval) const
2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (interval.empty())
2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return interval.hasNaN() ? "{ NaN }" : "{}";
2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (interval.lo() == interval.hi())
2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return (std::string(interval.hasNaN() ? "{ NaN, " : "{ ") +
2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				floatToHex(interval.lo()) + " }");
2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (interval == Interval::unbounded(true))
2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return "<any>";
2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return (std::string(interval.hasNaN() ? "{ NaN } | " : "") +
2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			"[" + floatToHex(interval.lo()) + ", " + floatToHex(interval.hi()) + "]");
2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate <typename T>
2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic FloatFormat nativeFormat (void)
2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	typedef std::numeric_limits<T> Limits;
2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(Limits::radix == 2);
2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return FloatFormat(Limits::min_exponent - 1,	// These have a built-in offset of one
2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					   Limits::max_exponent - 1,
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					   Limits::digits - 1,			// don't count the hidden bit
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					   Limits::has_denorm != std::denorm_absent,
2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					   Limits::has_infinity ? YES : NO,
2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					   Limits::has_quiet_NaN ? YES : NO,
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					   ((Limits::has_denorm == std::denorm_present) ? YES :
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						(Limits::has_denorm == std::denorm_absent) ? NO :
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						MAYBE));
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2883c827367444ee418f129b2c238299f49d3264554Jarkko PoyryFloatFormat	FloatFormat::nativeFloat (void)
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return nativeFormat<float>();
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2933c827367444ee418f129b2c238299f49d3264554Jarkko PoyryFloatFormat	FloatFormat::nativeDouble (void)
2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return nativeFormat<double>();
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::string;
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::ostringstream;
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing de::MovePtr;
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing de::UniquePtr;
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass Test
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							Test		(MovePtr<FloatFormat> fmt) : m_fmt(fmt) {}
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	double					p			(int e) const	 			{ return deLdExp(1.0, e); }
3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void					check		(const string&	expr,
3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										 double			result,
3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry										 double			reference) const;
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void					testULP		(double arg, double ref) const;
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void					testRound	(double arg, double refDown, double refUp) const;
3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	UniquePtr<FloatFormat>	m_fmt;
3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid Test::check (const string& expr, double result, double reference) const
3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (result != reference)
3243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		ostringstream oss;
3263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		oss << expr << " returned " << result << ", expected " << reference;
3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TCU_FAIL(oss.str().c_str());
3283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3313c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid Test::testULP (double arg, double ref) const
3323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ostringstream	oss;
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	oss << "ulp(" << arg << ")";
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	check(oss.str(), m_fmt->ulp(arg), ref);
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid Test::testRound (double arg, double refDown, double refUp) const
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		ostringstream oss;
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		oss << "round(" << arg << ", false)";
3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		check(oss.str(), m_fmt->round(arg, false), refDown);
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		ostringstream oss;
3483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		oss << "round(" << arg << ", true)";
3493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		check(oss.str(), m_fmt->round(arg, true), refUp);
3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass TestBinary32 : public Test
3543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
3563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			TestBinary32 (void)
3573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				: Test (MovePtr<FloatFormat>(new FloatFormat(-126, 127, 23, true))) {}
3583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void	runTest	(void) const;
3603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3623c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid TestBinary32::runTest (void) const
3633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testULP(p(0),				p(-24));
3653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testULP(p(0) + p(-23),		p(-23));
3663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testULP(p(-124),			p(-148));
3673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testULP(p(-125),			p(-149));
3683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testULP(p(-125) + p(-140),	p(-148));
3693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testULP(p(-126),			p(-149));
3703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testULP(p(-130),			p(-149));
3713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testRound(p(0) + p(-20) + p(-40),	p(0) + p(-20),		p(0) + p(-20) + p(-23));
3733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	testRound(p(-126) - p(-150),		p(-126) - p(-149),	p(-126));
3743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(m_fmt->floatToHex(p(0)) == "0x1.000000p0");
3763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(m_fmt->floatToHex(p(8) + p(-4)) == "0x1.001000p8");
3773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(m_fmt->floatToHex(p(-140)) == "0x0.000400p-126");
3783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(m_fmt->floatToHex(p(-140)) == "0x0.000400p-126");
3793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TCU_CHECK(m_fmt->floatToHex(p(-126) + p(-125)) == "0x1.800000p-125");
3803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // anonymous
3833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3843c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid FloatFormat_selfTest (void)
3853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TestBinary32	test32;
3873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	test32.runTest();
3883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // tcu
391