1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program Tester Core
3e5c31af7Sopenharmony_ci * ----------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Adjustable-precision floating point operations.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "tcuFloatFormat.hpp"
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci#include "deMath.h"
27e5c31af7Sopenharmony_ci#include "deUniquePtr.hpp"
28e5c31af7Sopenharmony_ci
29e5c31af7Sopenharmony_ci#include <sstream>
30e5c31af7Sopenharmony_ci#include <iomanip>
31e5c31af7Sopenharmony_ci#include <limits>
32e5c31af7Sopenharmony_ci
33e5c31af7Sopenharmony_cinamespace tcu
34e5c31af7Sopenharmony_ci{
35e5c31af7Sopenharmony_cinamespace
36e5c31af7Sopenharmony_ci{
37e5c31af7Sopenharmony_ci
38e5c31af7Sopenharmony_ciInterval chooseInterval(YesNoMaybe choice, const Interval& no, const Interval& yes)
39e5c31af7Sopenharmony_ci{
40e5c31af7Sopenharmony_ci	switch (choice)
41e5c31af7Sopenharmony_ci	{
42e5c31af7Sopenharmony_ci		case NO:	return no;
43e5c31af7Sopenharmony_ci		case YES:	return yes;
44e5c31af7Sopenharmony_ci		case MAYBE:	return no | yes;
45e5c31af7Sopenharmony_ci		default:	DE_FATAL("Impossible case");
46e5c31af7Sopenharmony_ci	}
47e5c31af7Sopenharmony_ci
48e5c31af7Sopenharmony_ci	return Interval();
49e5c31af7Sopenharmony_ci}
50e5c31af7Sopenharmony_ci
51e5c31af7Sopenharmony_cidouble computeMaxValue (int maxExp, int fractionBits)
52e5c31af7Sopenharmony_ci{
53e5c31af7Sopenharmony_ci	return (deLdExp(1.0, maxExp) +
54e5c31af7Sopenharmony_ci			deLdExp(double((1ull << fractionBits) - 1), maxExp - fractionBits));
55e5c31af7Sopenharmony_ci}
56e5c31af7Sopenharmony_ci
57e5c31af7Sopenharmony_ci} // anonymous
58e5c31af7Sopenharmony_ci
59e5c31af7Sopenharmony_ciFloatFormat::FloatFormat (int			minExp,
60e5c31af7Sopenharmony_ci						  int			maxExp,
61e5c31af7Sopenharmony_ci						  int			fractionBits,
62e5c31af7Sopenharmony_ci						  bool			exactPrecision,
63e5c31af7Sopenharmony_ci						  YesNoMaybe	hasSubnormal_,
64e5c31af7Sopenharmony_ci						  YesNoMaybe	hasInf_,
65e5c31af7Sopenharmony_ci						  YesNoMaybe	hasNaN_)
66e5c31af7Sopenharmony_ci	: m_minExp			(minExp)
67e5c31af7Sopenharmony_ci	, m_maxExp			(maxExp)
68e5c31af7Sopenharmony_ci	, m_fractionBits	(fractionBits)
69e5c31af7Sopenharmony_ci	, m_hasSubnormal	(hasSubnormal_)
70e5c31af7Sopenharmony_ci	, m_hasInf			(hasInf_)
71e5c31af7Sopenharmony_ci	, m_hasNaN			(hasNaN_)
72e5c31af7Sopenharmony_ci	, m_exactPrecision	(exactPrecision)
73e5c31af7Sopenharmony_ci	, m_maxValue		(computeMaxValue(maxExp, fractionBits))
74e5c31af7Sopenharmony_ci{
75e5c31af7Sopenharmony_ci	DE_ASSERT(minExp <= maxExp);
76e5c31af7Sopenharmony_ci}
77e5c31af7Sopenharmony_ci
78e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
79e5c31af7Sopenharmony_ci * On the definition of ULP
80e5c31af7Sopenharmony_ci *
81e5c31af7Sopenharmony_ci * The GLSL spec does not define ULP. However, it refers to IEEE 754, which
82e5c31af7Sopenharmony_ci * (reportedly) uses Harrison's definition:
83e5c31af7Sopenharmony_ci *
84e5c31af7Sopenharmony_ci * ULP(x) is the distance between the closest floating point numbers
85e5c31af7Sopenharmony_ci * a and be such that a <= x <= b and a != b
86e5c31af7Sopenharmony_ci *
87e5c31af7Sopenharmony_ci * Note that this means that when x = 2^n, ULP(x) = 2^(n-p-1), i.e. it is the
88e5c31af7Sopenharmony_ci * distance to the next lowest float, not next highest.
89e5c31af7Sopenharmony_ci *
90e5c31af7Sopenharmony_ci * Furthermore, it is assumed that ULP is calculated relative to the exact
91e5c31af7Sopenharmony_ci * value, not the approximation. This is because otherwise a less accurate
92e5c31af7Sopenharmony_ci * approximation could be closer in ULPs, because its ULPs are bigger.
93e5c31af7Sopenharmony_ci *
94e5c31af7Sopenharmony_ci * For details, see "On the definition of ulp(x)" by Jean-Michel Muller
95e5c31af7Sopenharmony_ci *
96e5c31af7Sopenharmony_ci *-----------------------------------------------------------------------*/
97e5c31af7Sopenharmony_ci
98e5c31af7Sopenharmony_cidouble FloatFormat::ulp (double x, double count) const
99e5c31af7Sopenharmony_ci{
100e5c31af7Sopenharmony_ci	int				exp		= 0;
101e5c31af7Sopenharmony_ci	const double	frac	= deFractExp(deAbs(x), &exp);
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci	if (deIsNaN(frac))
104e5c31af7Sopenharmony_ci		return TCU_NAN;
105e5c31af7Sopenharmony_ci	else if (deIsInf(frac))
106e5c31af7Sopenharmony_ci		return deLdExp(1.0, m_maxExp - m_fractionBits);
107e5c31af7Sopenharmony_ci	else if (frac == 1.0)
108e5c31af7Sopenharmony_ci	{
109e5c31af7Sopenharmony_ci		// Harrison's ULP: choose distance to closest (i.e. next lower) at binade
110e5c31af7Sopenharmony_ci		// boundary.
111e5c31af7Sopenharmony_ci		--exp;
112e5c31af7Sopenharmony_ci	}
113e5c31af7Sopenharmony_ci	else if (frac == 0.0)
114e5c31af7Sopenharmony_ci		exp = m_minExp;
115e5c31af7Sopenharmony_ci
116e5c31af7Sopenharmony_ci	// ULP cannot be lower than the smallest quantum.
117e5c31af7Sopenharmony_ci	exp = de::max(exp, m_minExp);
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci	{
120e5c31af7Sopenharmony_ci		const double		oneULP	= deLdExp(1.0, exp - m_fractionBits);
121e5c31af7Sopenharmony_ci		ScopedRoundingMode	ctx		(DE_ROUNDINGMODE_TO_POSITIVE_INF);
122e5c31af7Sopenharmony_ci
123e5c31af7Sopenharmony_ci		return oneULP * count;
124e5c31af7Sopenharmony_ci	}
125e5c31af7Sopenharmony_ci}
126e5c31af7Sopenharmony_ci
127e5c31af7Sopenharmony_ci//! Return the difference between the given nominal exponent and
128e5c31af7Sopenharmony_ci//! the exponent of the lowest significand bit of the
129e5c31af7Sopenharmony_ci//! representation of a number with this format.
130e5c31af7Sopenharmony_ci//! For normal numbers this is the number of significand bits, but
131e5c31af7Sopenharmony_ci//! for subnormals it is less and for values of exp where 2^exp is too
132e5c31af7Sopenharmony_ci//! small to represent it is <0
133e5c31af7Sopenharmony_ciint FloatFormat::exponentShift (int exp) const
134e5c31af7Sopenharmony_ci{
135e5c31af7Sopenharmony_ci	return m_fractionBits - de::max(m_minExp - exp, 0);
136e5c31af7Sopenharmony_ci}
137e5c31af7Sopenharmony_ci
138e5c31af7Sopenharmony_ci//! Return the number closest to `d` that is exactly representable with the
139e5c31af7Sopenharmony_ci//! significand bits and minimum exponent of the floatformat. Round up if
140e5c31af7Sopenharmony_ci//! `upward` is true, otherwise down.
141e5c31af7Sopenharmony_cidouble FloatFormat::round (double d, bool upward) const
142e5c31af7Sopenharmony_ci{
143e5c31af7Sopenharmony_ci	int				exp			= 0;
144e5c31af7Sopenharmony_ci	const double	frac		= deFractExp(d, &exp);
145e5c31af7Sopenharmony_ci	const int		shift		= exponentShift(exp);
146e5c31af7Sopenharmony_ci	const double	shiftFrac	= deLdExp(frac, shift);
147e5c31af7Sopenharmony_ci	const double	roundFrac	= upward ? deCeil(shiftFrac) : deFloor(shiftFrac);
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci	return deLdExp(roundFrac, exp - shift);
150e5c31af7Sopenharmony_ci}
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci//! Return the range of numbers that `d` might be converted to in the
153e5c31af7Sopenharmony_ci//! floatformat, given its limitations with infinities, subnormals and maximum
154e5c31af7Sopenharmony_ci//! exponent.
155e5c31af7Sopenharmony_ciInterval FloatFormat::clampValue (double d) const
156e5c31af7Sopenharmony_ci{
157e5c31af7Sopenharmony_ci	const double	rSign		= deSign(d);
158e5c31af7Sopenharmony_ci	int				rExp		= 0;
159e5c31af7Sopenharmony_ci
160e5c31af7Sopenharmony_ci	DE_ASSERT(!deIsNaN(d));
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci	deFractExp(d, &rExp);
163e5c31af7Sopenharmony_ci	if (rExp < m_minExp)
164e5c31af7Sopenharmony_ci		return chooseInterval(m_hasSubnormal, rSign * 0.0, d);
165e5c31af7Sopenharmony_ci	else if (deIsInf(d) || rExp > m_maxExp)
166e5c31af7Sopenharmony_ci		return chooseInterval(m_hasInf, rSign * getMaxValue(), rSign * TCU_INFINITY);
167e5c31af7Sopenharmony_ci
168e5c31af7Sopenharmony_ci	return Interval(d);
169e5c31af7Sopenharmony_ci}
170e5c31af7Sopenharmony_ci
171e5c31af7Sopenharmony_ci//! Return the range of numbers that might be used with this format to
172e5c31af7Sopenharmony_ci//! represent a number within `x`.
173e5c31af7Sopenharmony_ciInterval FloatFormat::convert (const Interval& x) const
174e5c31af7Sopenharmony_ci{
175e5c31af7Sopenharmony_ci	Interval ret;
176e5c31af7Sopenharmony_ci	Interval tmp = x;
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_ci	if (x.hasNaN())
179e5c31af7Sopenharmony_ci	{
180e5c31af7Sopenharmony_ci		// If NaN might be supported, NaN is a legal return value
181e5c31af7Sopenharmony_ci		if (m_hasNaN != NO)
182e5c31af7Sopenharmony_ci			ret |= TCU_NAN;
183e5c31af7Sopenharmony_ci
184e5c31af7Sopenharmony_ci		// If NaN might not be supported, any (non-NaN) value is legal,
185e5c31af7Sopenharmony_ci		// _subject_ to clamping. Hence we modify tmp, not ret.
186e5c31af7Sopenharmony_ci		if (m_hasNaN != YES)
187e5c31af7Sopenharmony_ci			tmp = Interval::unbounded();
188e5c31af7Sopenharmony_ci	}
189e5c31af7Sopenharmony_ci
190e5c31af7Sopenharmony_ci	// Round both bounds _inwards_ to closest representable values.
191e5c31af7Sopenharmony_ci	if (!tmp.empty())
192e5c31af7Sopenharmony_ci		ret |= clampValue(round(tmp.lo(), false)) | clampValue(round(tmp.hi(), true));
193e5c31af7Sopenharmony_ci
194e5c31af7Sopenharmony_ci	// If this format's precision is not exact, the (possibly out-of-bounds)
195e5c31af7Sopenharmony_ci	// original value is also a possible result.
196e5c31af7Sopenharmony_ci	if (!m_exactPrecision)
197e5c31af7Sopenharmony_ci		ret |= x;
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ci	return ret;
200e5c31af7Sopenharmony_ci}
201e5c31af7Sopenharmony_ci
202e5c31af7Sopenharmony_cidouble FloatFormat::roundOut (double d, bool upward, bool roundUnderOverflow) const
203e5c31af7Sopenharmony_ci{
204e5c31af7Sopenharmony_ci	int	exp	= 0;
205e5c31af7Sopenharmony_ci	deFractExp(d, &exp);
206e5c31af7Sopenharmony_ci
207e5c31af7Sopenharmony_ci	if (roundUnderOverflow && exp > m_maxExp && (upward == (d < 0.0)))
208e5c31af7Sopenharmony_ci		return deSign(d) * getMaxValue();
209e5c31af7Sopenharmony_ci	else
210e5c31af7Sopenharmony_ci		return round(d, upward);
211e5c31af7Sopenharmony_ci}
212e5c31af7Sopenharmony_ci
213e5c31af7Sopenharmony_ci//! Round output of an operation.
214e5c31af7Sopenharmony_ci//! \param roundUnderOverflow Can +/-inf rounded to min/max representable;
215e5c31af7Sopenharmony_ci//!							  should be false if any of operands was inf, true otherwise.
216e5c31af7Sopenharmony_ciInterval FloatFormat::roundOut (const Interval& x, bool roundUnderOverflow) const
217e5c31af7Sopenharmony_ci{
218e5c31af7Sopenharmony_ci	Interval ret = x.nan();
219e5c31af7Sopenharmony_ci
220e5c31af7Sopenharmony_ci	if (!x.empty())
221e5c31af7Sopenharmony_ci		ret |= Interval(roundOut(x.lo(), false, roundUnderOverflow),
222e5c31af7Sopenharmony_ci						roundOut(x.hi(), true, roundUnderOverflow));
223e5c31af7Sopenharmony_ci
224e5c31af7Sopenharmony_ci	return ret;
225e5c31af7Sopenharmony_ci}
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_cistd::string	FloatFormat::floatToHex	(double x) const
228e5c31af7Sopenharmony_ci{
229e5c31af7Sopenharmony_ci	if (deIsNaN(x))
230e5c31af7Sopenharmony_ci		return "NaN";
231e5c31af7Sopenharmony_ci	else if (deIsInf(x))
232e5c31af7Sopenharmony_ci		return (x < 0.0 ? "-" : "+") + std::string("inf");
233e5c31af7Sopenharmony_ci	else if (x == 0.0) // \todo [2014-03-27 lauri] Negative zero
234e5c31af7Sopenharmony_ci		return "0.0";
235e5c31af7Sopenharmony_ci
236e5c31af7Sopenharmony_ci	int					exp			= 0;
237e5c31af7Sopenharmony_ci	const double		frac		= deFractExp(deAbs(x), &exp);
238e5c31af7Sopenharmony_ci	const int			shift		= exponentShift(exp);
239e5c31af7Sopenharmony_ci	const deUint64		bits		= deUint64(deLdExp(frac, shift));
240e5c31af7Sopenharmony_ci	const deUint64		whole		= bits >> m_fractionBits;
241e5c31af7Sopenharmony_ci	const deUint64		fraction	= bits & ((deUint64(1) << m_fractionBits) - 1);
242e5c31af7Sopenharmony_ci	const int			exponent	= exp + m_fractionBits - shift;
243e5c31af7Sopenharmony_ci	const int			numDigits	= (m_fractionBits + 3) / 4;
244e5c31af7Sopenharmony_ci	const deUint64		aligned		= fraction << (numDigits * 4 - m_fractionBits);
245e5c31af7Sopenharmony_ci	std::ostringstream	oss;
246e5c31af7Sopenharmony_ci
247e5c31af7Sopenharmony_ci	oss << (x < 0 ? "-" : "")
248e5c31af7Sopenharmony_ci		<< "0x" << whole << "."
249e5c31af7Sopenharmony_ci		<< std::hex << std::setw(numDigits) << std::setfill('0') << aligned
250e5c31af7Sopenharmony_ci		<< "p" << std::dec << std::setw(0) << exponent;
251e5c31af7Sopenharmony_ci
252e5c31af7Sopenharmony_ci	return oss.str();
253e5c31af7Sopenharmony_ci}
254e5c31af7Sopenharmony_ci
255e5c31af7Sopenharmony_cistd::string FloatFormat::intervalToHex (const Interval& interval) const
256e5c31af7Sopenharmony_ci{
257e5c31af7Sopenharmony_ci	if (interval.empty())
258e5c31af7Sopenharmony_ci		return interval.hasNaN() ? "{ NaN }" : "{}";
259e5c31af7Sopenharmony_ci
260e5c31af7Sopenharmony_ci	else if (interval.lo() == interval.hi())
261e5c31af7Sopenharmony_ci		return (std::string(interval.hasNaN() ? "{ NaN, " : "{ ") +
262e5c31af7Sopenharmony_ci				floatToHex(interval.lo()) + " }");
263e5c31af7Sopenharmony_ci	else if (interval == Interval::unbounded(true))
264e5c31af7Sopenharmony_ci		return "<any>";
265e5c31af7Sopenharmony_ci
266e5c31af7Sopenharmony_ci	return (std::string(interval.hasNaN() ? "{ NaN } | " : "") +
267e5c31af7Sopenharmony_ci			"[" + floatToHex(interval.lo()) + ", " + floatToHex(interval.hi()) + "]");
268e5c31af7Sopenharmony_ci}
269e5c31af7Sopenharmony_ci
270e5c31af7Sopenharmony_citemplate <typename T>
271e5c31af7Sopenharmony_cistatic FloatFormat nativeFormat (void)
272e5c31af7Sopenharmony_ci{
273e5c31af7Sopenharmony_ci	typedef std::numeric_limits<T> Limits;
274e5c31af7Sopenharmony_ci
275e5c31af7Sopenharmony_ci	DE_ASSERT(Limits::radix == 2);
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_ci	return FloatFormat(Limits::min_exponent - 1,	// These have a built-in offset of one
278e5c31af7Sopenharmony_ci					   Limits::max_exponent - 1,
279e5c31af7Sopenharmony_ci					   Limits::digits - 1,			// don't count the hidden bit
280e5c31af7Sopenharmony_ci					   Limits::has_denorm != std::denorm_absent,
281e5c31af7Sopenharmony_ci					   Limits::has_infinity ? YES : NO,
282e5c31af7Sopenharmony_ci					   Limits::has_quiet_NaN ? YES : NO,
283e5c31af7Sopenharmony_ci					   ((Limits::has_denorm == std::denorm_present) ? YES :
284e5c31af7Sopenharmony_ci						(Limits::has_denorm == std::denorm_absent) ? NO :
285e5c31af7Sopenharmony_ci						MAYBE));
286e5c31af7Sopenharmony_ci}
287e5c31af7Sopenharmony_ci
288e5c31af7Sopenharmony_ciFloatFormat	FloatFormat::nativeFloat (void)
289e5c31af7Sopenharmony_ci{
290e5c31af7Sopenharmony_ci	return nativeFormat<float>();
291e5c31af7Sopenharmony_ci}
292e5c31af7Sopenharmony_ci
293e5c31af7Sopenharmony_ciFloatFormat	FloatFormat::nativeDouble (void)
294e5c31af7Sopenharmony_ci{
295e5c31af7Sopenharmony_ci	return nativeFormat<double>();
296e5c31af7Sopenharmony_ci}
297e5c31af7Sopenharmony_ci
298e5c31af7Sopenharmony_ciNormalizedFormat::NormalizedFormat (int		fractionBits)
299e5c31af7Sopenharmony_ci	: FloatFormat(0, 0, fractionBits, true, tcu::YES)
300e5c31af7Sopenharmony_ci{
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_ci}
303e5c31af7Sopenharmony_ci
304e5c31af7Sopenharmony_cidouble NormalizedFormat::round(double d, bool upward) const
305e5c31af7Sopenharmony_ci{
306e5c31af7Sopenharmony_ci	const int fractionBits = getFractionBits();
307e5c31af7Sopenharmony_ci
308e5c31af7Sopenharmony_ci	if (fractionBits <= 0)
309e5c31af7Sopenharmony_ci		return d;
310e5c31af7Sopenharmony_ci
311e5c31af7Sopenharmony_ci	const int maxIntValue = (1 << fractionBits) - 1;
312e5c31af7Sopenharmony_ci	const double value = d * maxIntValue;
313e5c31af7Sopenharmony_ci	const double normValue = upward ? deCeil(value) : deFloor(value);
314e5c31af7Sopenharmony_ci	return normValue / maxIntValue;
315e5c31af7Sopenharmony_ci}
316e5c31af7Sopenharmony_ci
317e5c31af7Sopenharmony_cidouble NormalizedFormat::ulp(double x, double count) const
318e5c31af7Sopenharmony_ci{
319e5c31af7Sopenharmony_ci	(void) x;
320e5c31af7Sopenharmony_ci
321e5c31af7Sopenharmony_ci	const int maxIntValue = (1 << getFractionBits()) - 1;
322e5c31af7Sopenharmony_ci	const double precision = 1.0 / maxIntValue;
323e5c31af7Sopenharmony_ci	return precision * count;
324e5c31af7Sopenharmony_ci}
325e5c31af7Sopenharmony_ci
326e5c31af7Sopenharmony_cidouble NormalizedFormat::roundOut (double d, bool upward, bool roundUnderOverflow) const
327e5c31af7Sopenharmony_ci{
328e5c31af7Sopenharmony_ci	if (roundUnderOverflow && deAbs(d) > 1.0 && (upward == (d < 0.0)))
329e5c31af7Sopenharmony_ci		return deSign(d);
330e5c31af7Sopenharmony_ci	else
331e5c31af7Sopenharmony_ci		return round(d, upward);
332e5c31af7Sopenharmony_ci}
333e5c31af7Sopenharmony_ci
334e5c31af7Sopenharmony_cinamespace
335e5c31af7Sopenharmony_ci{
336e5c31af7Sopenharmony_ci
337e5c31af7Sopenharmony_ciusing std::string;
338e5c31af7Sopenharmony_ciusing std::ostringstream;
339e5c31af7Sopenharmony_ciusing de::MovePtr;
340e5c31af7Sopenharmony_ciusing de::UniquePtr;
341e5c31af7Sopenharmony_ci
342e5c31af7Sopenharmony_ciclass Test
343e5c31af7Sopenharmony_ci{
344e5c31af7Sopenharmony_ciprotected:
345e5c31af7Sopenharmony_ci
346e5c31af7Sopenharmony_ci							Test		(MovePtr<FloatFormat> fmt) : m_fmt(fmt) {}
347e5c31af7Sopenharmony_ci	double					p			(int e) const				{ return deLdExp(1.0, e); }
348e5c31af7Sopenharmony_ci	void					check		(const string&	expr,
349e5c31af7Sopenharmony_ci										 double			result,
350e5c31af7Sopenharmony_ci										 double			reference) const;
351e5c31af7Sopenharmony_ci	void					testULP		(double arg, double ref) const;
352e5c31af7Sopenharmony_ci	void					testRound	(double arg, double refDown, double refUp) const;
353e5c31af7Sopenharmony_ci
354e5c31af7Sopenharmony_ci	UniquePtr<FloatFormat>	m_fmt;
355e5c31af7Sopenharmony_ci};
356e5c31af7Sopenharmony_ci
357e5c31af7Sopenharmony_civoid Test::check (const string& expr, double result, double reference) const
358e5c31af7Sopenharmony_ci{
359e5c31af7Sopenharmony_ci	if (result != reference)
360e5c31af7Sopenharmony_ci	{
361e5c31af7Sopenharmony_ci		ostringstream oss;
362e5c31af7Sopenharmony_ci		oss << expr << " returned " << result << ", expected " << reference;
363e5c31af7Sopenharmony_ci		TCU_FAIL(oss.str().c_str());
364e5c31af7Sopenharmony_ci	}
365e5c31af7Sopenharmony_ci}
366e5c31af7Sopenharmony_ci
367e5c31af7Sopenharmony_civoid Test::testULP (double arg, double ref) const
368e5c31af7Sopenharmony_ci{
369e5c31af7Sopenharmony_ci	ostringstream	oss;
370e5c31af7Sopenharmony_ci
371e5c31af7Sopenharmony_ci	oss << "ulp(" << arg << ")";
372e5c31af7Sopenharmony_ci	check(oss.str(), m_fmt->ulp(arg), ref);
373e5c31af7Sopenharmony_ci}
374e5c31af7Sopenharmony_ci
375e5c31af7Sopenharmony_civoid Test::testRound (double arg, double refDown, double refUp) const
376e5c31af7Sopenharmony_ci{
377e5c31af7Sopenharmony_ci	{
378e5c31af7Sopenharmony_ci		ostringstream oss;
379e5c31af7Sopenharmony_ci		oss << "round(" << arg << ", false)";
380e5c31af7Sopenharmony_ci		check(oss.str(), m_fmt->round(arg, false), refDown);
381e5c31af7Sopenharmony_ci	}
382e5c31af7Sopenharmony_ci	{
383e5c31af7Sopenharmony_ci		ostringstream oss;
384e5c31af7Sopenharmony_ci		oss << "round(" << arg << ", true)";
385e5c31af7Sopenharmony_ci		check(oss.str(), m_fmt->round(arg, true), refUp);
386e5c31af7Sopenharmony_ci	}
387e5c31af7Sopenharmony_ci}
388e5c31af7Sopenharmony_ci
389e5c31af7Sopenharmony_ciclass TestBinary32 : public Test
390e5c31af7Sopenharmony_ci{
391e5c31af7Sopenharmony_cipublic:
392e5c31af7Sopenharmony_ci			TestBinary32 (void)
393e5c31af7Sopenharmony_ci				: Test (MovePtr<FloatFormat>(new FloatFormat(-126, 127, 23, true))) {}
394e5c31af7Sopenharmony_ci
395e5c31af7Sopenharmony_ci	void	runTest	(void) const;
396e5c31af7Sopenharmony_ci};
397e5c31af7Sopenharmony_ci
398e5c31af7Sopenharmony_civoid TestBinary32::runTest (void) const
399e5c31af7Sopenharmony_ci{
400e5c31af7Sopenharmony_ci	testULP(p(0),				p(-24));
401e5c31af7Sopenharmony_ci	testULP(p(0) + p(-23),		p(-23));
402e5c31af7Sopenharmony_ci	testULP(p(-124),			p(-148));
403e5c31af7Sopenharmony_ci	testULP(p(-125),			p(-149));
404e5c31af7Sopenharmony_ci	testULP(p(-125) + p(-140),	p(-148));
405e5c31af7Sopenharmony_ci	testULP(p(-126),			p(-149));
406e5c31af7Sopenharmony_ci	testULP(p(-130),			p(-149));
407e5c31af7Sopenharmony_ci
408e5c31af7Sopenharmony_ci	testRound(p(0) + p(-20) + p(-40),	p(0) + p(-20),		p(0) + p(-20) + p(-23));
409e5c31af7Sopenharmony_ci	testRound(p(-126) - p(-150),		p(-126) - p(-149),	p(-126));
410e5c31af7Sopenharmony_ci
411e5c31af7Sopenharmony_ci	TCU_CHECK(m_fmt->floatToHex(p(0)) == "0x1.000000p0");
412e5c31af7Sopenharmony_ci	TCU_CHECK(m_fmt->floatToHex(p(8) + p(-4)) == "0x1.001000p8");
413e5c31af7Sopenharmony_ci	TCU_CHECK(m_fmt->floatToHex(p(-140)) == "0x0.000400p-126");
414e5c31af7Sopenharmony_ci	TCU_CHECK(m_fmt->floatToHex(p(-140)) == "0x0.000400p-126");
415e5c31af7Sopenharmony_ci	TCU_CHECK(m_fmt->floatToHex(p(-126) + p(-125)) == "0x1.800000p-125");
416e5c31af7Sopenharmony_ci}
417e5c31af7Sopenharmony_ci
418e5c31af7Sopenharmony_ci} // anonymous
419e5c31af7Sopenharmony_ci
420e5c31af7Sopenharmony_civoid FloatFormat_selfTest (void)
421e5c31af7Sopenharmony_ci{
422e5c31af7Sopenharmony_ci	TestBinary32	test32;
423e5c31af7Sopenharmony_ci	test32.runTest();
424e5c31af7Sopenharmony_ci}
425e5c31af7Sopenharmony_ci
426e5c31af7Sopenharmony_ci} // tcu
427