3 /*-------------------------------------------------------------------------
4 * drawElements Quality Program Tester Core
5 * ----------------------------------------
7 * Copyright 2014 The Android Open Source Project
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Reconfigurable floating-point value template.
24 *//*--------------------------------------------------------------------*/
26 #include "tcuDefs.hpp"
36 FLOAT_HAS_SIGN = (1<<0),
37 FLOAT_SUPPORT_DENORM = (1<<1)
40 /*--------------------------------------------------------------------*//*!
41 * \brief Floating-point format template
43 * This template implements arbitrary floating-point handling. Template
44 * can be used for conversion between different formats and checking
45 * various properties of floating-point values.
46 *//*--------------------------------------------------------------------*/
47 template <typename StorageType_, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
51 typedef StorageType_ StorageType;
55 EXPONENT_BITS = ExponentBits,
56 MANTISSA_BITS = MantissaBits,
57 EXPONENT_BIAS = ExponentBias,
62 explicit Float (StorageType value);
63 explicit Float (float v);
64 explicit Float (double v);
66 template <typename OtherStorageType, int OtherExponentBits, int OtherMantissaBits, int OtherExponentBias, deUint32 OtherFlags>
67 static Float convert (const Float<OtherStorageType, OtherExponentBits, OtherMantissaBits, OtherExponentBias, OtherFlags>& src);
69 static inline Float convert (const Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>& src) { return src; }
71 /*--------------------------------------------------------------------*//*!
72 * \brief Construct floating point value
73 * \param sign Sign. Must be +1/-1
74 * \param exponent Exponent in range [1-ExponentBias, ExponentBias+1]
75 * \param mantissa Mantissa bits with implicit leading bit explicitly set
76 * \return The specified float
78 * This function constructs a floating point value from its inputs.
79 * The normally implicit leading bit of the mantissa must be explicitly set.
80 * The exponent normally used for zero/subnormals is an invalid input. Such
81 * values are specified with the leading mantissa bit of zero and the lowest
82 * normal exponent (1-ExponentBias). Additionally having both exponent and
83 * mantissa set to zero is a shorthand notation for the correctly signed
84 * floating point zero. Inf and NaN must be specified directly with an
85 * exponent of ExponentBias+1 and the appropriate mantissa (with leading
87 *//*--------------------------------------------------------------------*/
88 static inline Float construct (int sign, int exponent, StorageType mantissa);
90 /*--------------------------------------------------------------------*//*!
91 * \brief Construct floating point value. Explicit version
92 * \param sign Sign. Must be +1/-1
93 * \param exponent Exponent in range [-ExponentBias, ExponentBias+1]
94 * \param mantissa Mantissa bits
95 * \return The specified float
97 * This function constructs a floating point value from its inputs with
98 * minimal intervention.
99 * The sign is turned into a sign bit and the exponent bias is added.
100 * See IEEE-754 for additional information on the inputs and
101 * the encoding of special values.
102 *//*--------------------------------------------------------------------*/
103 static Float constructBits (int sign, int exponent, StorageType mantissaBits);
105 StorageType bits (void) const { return m_value; }
106 float asFloat (void) const;
107 double asDouble (void) const;
109 inline int signBit (void) const { return (int)(m_value >> (ExponentBits+MantissaBits)) & 1; }
110 inline StorageType exponentBits (void) const { return (m_value >> MantissaBits) & ((StorageType(1)<<ExponentBits)-1); }
111 inline StorageType mantissaBits (void) const { return m_value & ((StorageType(1)<<MantissaBits)-1); }
113 inline int sign (void) const { return signBit() ? -1 : 1; }
114 inline int exponent (void) const { return isDenorm() ? 1 - ExponentBias : (int)exponentBits() - ExponentBias; }
115 inline StorageType mantissa (void) const { return isZero() || isDenorm() ? mantissaBits() : (mantissaBits() | (StorageType(1)<<MantissaBits)); }
117 inline bool isInf (void) const { return exponentBits() == ((1<<ExponentBits)-1) && mantissaBits() == 0; }
118 inline bool isNaN (void) const { return exponentBits() == ((1<<ExponentBits)-1) && mantissaBits() != 0; }
119 inline bool isZero (void) const { return exponentBits() == 0 && mantissaBits() == 0; }
120 inline bool isDenorm (void) const { return exponentBits() == 0 && mantissaBits() != 0; }
122 static Float zero (int sign);
123 static Float inf (int sign);
124 static Float nan (void);
128 } DE_WARN_UNUSED_TYPE;
130 // Common floating-point types.
131 typedef Float<deUint16, 5, 10, 15, FLOAT_HAS_SIGN|FLOAT_SUPPORT_DENORM> Float16; //!< IEEE 754-2008 16-bit floating-point value
132 typedef Float<deUint32, 8, 23, 127, FLOAT_HAS_SIGN|FLOAT_SUPPORT_DENORM> Float32; //!< IEEE 754 32-bit floating-point value
133 typedef Float<deUint64, 11, 52, 1023, FLOAT_HAS_SIGN|FLOAT_SUPPORT_DENORM> Float64; //!< IEEE 754 64-bit floating-point value
135 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
136 inline Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::Float (void)
141 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
142 inline Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::Float (StorageType value)
147 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
148 inline Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::Float (float value)
152 memcpy(&u32, &value, sizeof(deUint32));
153 *this = convert(Float32(u32));
156 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
157 inline Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::Float (double value)
161 memcpy(&u64, &value, sizeof(deUint64));
162 *this = convert(Float64(u64));
165 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
166 inline float Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::asFloat (void) const
169 deUint32 u32 = Float32::convert(*this).bits();
170 memcpy(&v, &u32, sizeof(deUint32));
174 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
175 inline double Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::asDouble (void) const
178 deUint64 u64 = Float64::convert(*this).bits();
179 memcpy(&v, &u64, sizeof(deUint64));
183 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
184 inline Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags> Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::zero (int sign)
186 DE_ASSERT(sign == 1 || ((Flags & FLOAT_HAS_SIGN) && sign == -1));
187 return Float(StorageType((sign > 0 ? 0ull : 1ull) << (ExponentBits+MantissaBits)));
190 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
191 inline Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags> Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::inf (int sign)
193 DE_ASSERT(sign == 1 || ((Flags & FLOAT_HAS_SIGN) && sign == -1));
194 return Float(StorageType(((sign > 0 ? 0ull : 1ull) << (ExponentBits+MantissaBits)) | (((1ull<<ExponentBits)-1) << MantissaBits)));
197 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
198 inline Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags> Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::nan (void)
200 return Float(StorageType((1ull<<(ExponentBits+MantissaBits))-1));
203 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
204 Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>
205 Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::construct
206 (int sign, int exponent, StorageType mantissa)
208 // Repurpose this otherwise invalid input as a shorthand notation for zero (no need for caller to care about internal representation)
209 const bool isShorthandZero = exponent == 0 && mantissa == 0;
211 // Handles the typical notation for zero (min exponent, mantissa 0). Note that the exponent usually used exponent (-ExponentBias) for zero/subnormals is not used.
212 // Instead zero/subnormals have the (normally implicit) leading mantissa bit set to zero.
213 const bool isDenormOrZero = (exponent == 1 - ExponentBias) && (mantissa >> MantissaBits == 0);
214 const StorageType s = StorageType((StorageType(sign < 0 ? 1 : 0)) << (StorageType(ExponentBits+MantissaBits)));
215 const StorageType exp = (isShorthandZero || isDenormOrZero) ? StorageType(0) : StorageType(exponent + ExponentBias);
217 DE_ASSERT(sign == +1 || sign == -1);
218 DE_ASSERT(isShorthandZero || isDenormOrZero || mantissa >> MantissaBits == 1);
219 DE_ASSERT(exp >> ExponentBits == 0);
221 return Float(StorageType(s | (exp << MantissaBits) | (mantissa & ((StorageType(1)<<MantissaBits)-1))));
224 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
225 Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>
226 Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::constructBits
227 (int sign, int exponent, StorageType mantissaBits)
229 const StorageType signBit = sign < 0 ? 1 : 0;
230 const StorageType exponentBits = exponent + ExponentBias;
232 DE_ASSERT(sign == +1 || sign == -1 );
233 DE_ASSERT(exponentBits >> ExponentBits == 0);
234 DE_ASSERT(mantissaBits >> MantissaBits == 0);
236 return Float(StorageType((signBit << (ExponentBits+MantissaBits)) | (exponentBits << MantissaBits) | (mantissaBits)));
239 template <typename StorageType, int ExponentBits, int MantissaBits, int ExponentBias, deUint32 Flags>
240 template <typename OtherStorageType, int OtherExponentBits, int OtherMantissaBits, int OtherExponentBias, deUint32 OtherFlags>
241 Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>
242 Float<StorageType, ExponentBits, MantissaBits, ExponentBias, Flags>::convert
243 (const Float<OtherStorageType, OtherExponentBits, OtherMantissaBits, OtherExponentBias, OtherFlags>& other)
245 if (!(Flags & FLOAT_HAS_SIGN) && other.sign() < 0)
247 // Negative number, truncate to zero.
250 else if (other.isInf())
252 return inf(other.sign());
254 else if (other.isNaN())
258 else if (other.isZero())
260 return zero(other.sign());
264 const int eMin = 1 - ExponentBias;
265 const int eMax = ((1<<ExponentBits)-2) - ExponentBias;
267 const StorageType s = StorageType((StorageType(other.signBit())) << (StorageType(ExponentBits+MantissaBits))); // \note Not sign, but sign bit.
268 int e = other.exponent();
269 deUint64 m = other.mantissa();
271 // Normalize denormalized values prior to conversion.
272 while (!(m & (1ull<<OtherMantissaBits)))
281 if ((Flags & FLOAT_SUPPORT_DENORM) && (eMin-e-1 <= MantissaBits))
283 // Shift and round (RTE).
284 int bitDiff = (OtherMantissaBits-MantissaBits) + (eMin-e);
285 deUint64 half = (1ull << (bitDiff - 1)) - 1;
286 deUint64 bias = (m >> bitDiff) & 1;
288 return Float(StorageType(s | (m + half + bias) >> bitDiff));
291 return zero(other.sign());
296 m = m & ~(1ull<<OtherMantissaBits);
298 if (MantissaBits < OtherMantissaBits)
300 // Round mantissa (round to nearest even).
301 int bitDiff = OtherMantissaBits-MantissaBits;
302 deUint64 half = (1ull << (bitDiff - 1)) - 1;
303 deUint64 bias = (m >> bitDiff) & 1;
305 m = (m + half + bias) >> bitDiff;
307 if (m & (1ull<<MantissaBits))
309 // Overflow in mantissa.
316 int bitDiff = MantissaBits-OtherMantissaBits;
323 return inf(other.sign());
327 DE_ASSERT(de::inRange(e, eMin, eMax));
328 DE_ASSERT(((e + ExponentBias) & ~((1ull<<ExponentBits)-1)) == 0);
329 DE_ASSERT((m & ~((1ull<<MantissaBits)-1)) == 0);
331 return Float(StorageType(s | (StorageType(e + ExponentBias) << MantissaBits) | m));
339 #endif // _TCUFLOAT_HPP