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