xref: /aosp_15_r20/external/deqp/framework/common/tcuFloatFormat.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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