1 |
|
/* |
2 |
|
** Copyright (C) 2018 Martin Brain |
3 |
|
** |
4 |
|
** See the file LICENSE for licensing information. |
5 |
|
*/ |
6 |
|
|
7 |
|
/* |
8 |
|
** unpackedFloat.h |
9 |
|
** |
10 |
|
** Martin Brain |
11 |
|
** martin.brain@cs.ox.ac.uk |
12 |
|
** 03/06/14 |
13 |
|
** |
14 |
|
** The working representation of a floating-point number. This is |
15 |
|
** from the packed representation in a few ways: |
16 |
|
** |
17 |
|
** 1. Explicit flags for NaN, Inf and Zero. |
18 |
|
** 2. Significand is biased. |
19 |
|
** 3. Hidden bit is explicit. |
20 |
|
** 4. Subnormals are normalised. |
21 |
|
** |
22 |
|
** This makes numbers more uniform and makes it easier to implement |
23 |
|
** compact and efficient algorithms. |
24 |
|
*/ |
25 |
|
|
26 |
|
#include "symfpu/utils/common.h" |
27 |
|
#include "symfpu/utils/properties.h" |
28 |
|
#include "symfpu/utils/numberOfRoundingModes.h" |
29 |
|
|
30 |
|
#include "symfpu/core/ite.h" |
31 |
|
#include "symfpu/core/operations.h" |
32 |
|
|
33 |
|
// For debugging only |
34 |
|
#include <iostream> |
35 |
|
|
36 |
|
#ifndef SYMFPU_UNPACKED_FLOAT |
37 |
|
#define SYMFPU_UNPACKED_FLOAT |
38 |
|
|
39 |
|
namespace symfpu { |
40 |
|
|
41 |
|
template<class t> |
42 |
36199 |
class unpackedFloat { |
43 |
|
public : |
44 |
|
// Typedef the names from the traits for convenience |
45 |
|
typedef typename t::bwt bwt; |
46 |
|
typedef typename t::fpt fpt; |
47 |
|
typedef typename t::prop prop; |
48 |
|
typedef typename t::sbv sbv; |
49 |
|
typedef typename t::ubv ubv; |
50 |
|
|
51 |
|
|
52 |
|
protected : |
53 |
|
// TODO : protect these again |
54 |
|
public : |
55 |
|
prop nan; |
56 |
|
prop inf; |
57 |
|
prop zero; |
58 |
|
|
59 |
|
prop sign; |
60 |
|
sbv exponent; |
61 |
|
ubv significand; |
62 |
|
protected : |
63 |
|
|
64 |
|
// It is possible, but hopefully as difficult as possible to create, |
65 |
|
// via the constructor an invalid unpacked float |
66 |
|
|
67 |
|
// A piecewise / literal constructor using fpclass |
68 |
|
enum fpclass { FPCLASS_NAN, FPCLASS_INF, FPCLASS_ZERO, FPCLASS_NUMBER }; |
69 |
|
|
70 |
7552 |
unpackedFloat (const fpclass c, const prop &s, const sbv &exp, const ubv &signif) : |
71 |
21420 |
nan(c == FPCLASS_NAN), inf(c == FPCLASS_INF), zero(c == FPCLASS_ZERO), |
72 |
21832 |
sign(s), exponent(exp), significand(signif) |
73 |
7552 |
{} |
74 |
|
|
75 |
|
|
76 |
|
// Should only be used by ite |
77 |
|
friend ite<prop, unpackedFloat<t> >; |
78 |
|
|
79 |
|
// TODO : See above -- this should only be used by ite |
80 |
|
public : |
81 |
14419 |
unpackedFloat (const prop &iteNaN, const prop &iteInf, const prop &iteZero, |
82 |
|
const prop &iteSign, const sbv &iteExponent, const ubv &iteSignificand) : |
83 |
|
nan(iteNaN), inf(iteInf), zero(iteZero), |
84 |
14419 |
sign(iteSign), exponent(iteExponent), significand(iteSignificand) |
85 |
14419 |
{} |
86 |
|
private : |
87 |
|
|
88 |
|
// Used for special values |
89 |
|
// However this will also be passed through the operations, thus |
90 |
|
// if it is also a valid normal number then it will make proving |
91 |
|
// invariants easier. In this case it is the value 1.0. |
92 |
|
|
93 |
32017 |
static sbv defaultExponent(const fpt &fmt) { |
94 |
32017 |
return sbv::zero(unpackedFloat<t>::exponentWidth(fmt)); |
95 |
|
} |
96 |
|
|
97 |
30998 |
static ubv defaultSignificand(const fpt &fmt) { |
98 |
30998 |
bwt significandWidth = unpackedFloat<t>::significandWidth(fmt); |
99 |
|
|
100 |
30998 |
return ubv::one(significandWidth) << ubv(significandWidth, (significandWidth - 1)); |
101 |
|
} |
102 |
|
|
103 |
|
|
104 |
|
|
105 |
|
public : |
106 |
5403 |
unpackedFloat (const prop &s, const sbv &exp, const ubv &signif) : |
107 |
|
nan(false), inf(false), zero(false), |
108 |
5403 |
sign(s), exponent(exp), significand(signif) |
109 |
5403 |
{} |
110 |
|
|
111 |
|
// An intermediate point in some operations is producing a value in an extended |
112 |
|
// format (for example, multiply produces an intermediate value with one extra exponent |
113 |
|
// bit and double the number of significand bits). However the unpacked size of the |
114 |
|
// significand is larger than the bits given by the format. This constructor does |
115 |
|
// the appropriate extension so that what is constructed is a valid unpacked float |
116 |
|
// in the given format. |
117 |
1019 |
unpackedFloat (const fpt &fmt, const prop &s, const sbv &exp, const ubv &signif) : |
118 |
|
nan(false), inf(false), zero(false), |
119 |
1019 |
sign(s), exponent(exp.matchWidth(defaultExponent(fmt))), significand(signif) |
120 |
1019 |
{} |
121 |
|
|
122 |
6109 |
unpackedFloat (const unpackedFloat<t> &old) : |
123 |
15066 |
nan(old.nan), inf(old.inf), zero(old.zero), |
124 |
16153 |
sign(old.sign), exponent(old.exponent), significand(old.significand) |
125 |
6109 |
{} |
126 |
|
|
127 |
|
// Copy and over-write sign |
128 |
919 |
unpackedFloat (const unpackedFloat<t> &old, const prop &s) : |
129 |
2532 |
nan(old.nan), inf(old.inf), zero(old.zero), |
130 |
2607 |
sign(ITE(old.nan, old.sign, s)), exponent(old.exponent), significand(old.significand) |
131 |
919 |
{} |
132 |
|
|
133 |
|
// Swap back-ends |
134 |
|
template <class s> friend class unpackedFloat; |
135 |
|
|
136 |
|
template <class s> |
137 |
257 |
unpackedFloat (const unpackedFloat<s> &old) : |
138 |
771 |
nan(old.nan), inf(old.inf), zero(old.zero), |
139 |
1028 |
sign(old.sign), exponent(old.exponent), significand(old.significand) |
140 |
257 |
{} |
141 |
|
|
142 |
|
|
143 |
3476 |
static unpackedFloat<t> makeZero(const fpt &fmt, const prop &s) { |
144 |
3476 |
return unpackedFloat<t>(FPCLASS_ZERO, s, defaultExponent(fmt), defaultSignificand(fmt)); |
145 |
|
} |
146 |
|
|
147 |
2528 |
static unpackedFloat<t> makeInf(const fpt &fmt, const prop &s) { |
148 |
2528 |
return unpackedFloat<t>(FPCLASS_INF, s, defaultExponent(fmt), defaultSignificand(fmt)); |
149 |
|
} |
150 |
|
|
151 |
1548 |
static unpackedFloat<t> makeNaN(const fpt &fmt) { |
152 |
1548 |
return unpackedFloat<t>(FPCLASS_NAN, false, defaultExponent(fmt), defaultSignificand(fmt)); |
153 |
|
} |
154 |
|
|
155 |
28477 |
inline const prop & getNaN(void) const { return this->nan; } |
156 |
23207 |
inline const prop & getInf(void) const { return this->inf; } |
157 |
24484 |
inline const prop & getZero(void) const { return this->zero; } |
158 |
31943 |
inline const prop & getSign(void) const { return this->sign; } |
159 |
17437 |
inline const sbv & getExponent(void) const { return this->exponent; } |
160 |
20034 |
inline const ubv & getSignificand(void) const { return this->significand; } |
161 |
|
|
162 |
|
// inline unpackedFloat<t> changeSign(const prop &newSign) { |
163 |
|
// return unpackedFloat<t>(*this, newSign); |
164 |
|
// } |
165 |
|
|
166 |
|
|
167 |
|
|
168 |
|
|
169 |
|
// Get the number of bits in the unpacked format corresponding to a |
170 |
|
// given packed format. These are the unpacked counter-parts of |
171 |
|
// format.exponentWidth() and format.significandWidth() |
172 |
|
|
173 |
364901 |
static bwt exponentWidth(const fpt &format) { |
174 |
|
|
175 |
|
// This calculation is a little more complex than you might think... |
176 |
|
|
177 |
|
// Note that there is one more exponent above 0 than there is |
178 |
|
// below. This is the opposite of 2's compliment but this is not |
179 |
|
// a problem because the highest packed exponent corresponds to |
180 |
|
// inf and NaN and is thus does not need to be represented in the |
181 |
|
// unpacked format. |
182 |
|
// However we do need to increase it to allow subnormals (packed) |
183 |
|
// to be normalised. |
184 |
|
|
185 |
|
// The smallest exponent is: |
186 |
|
// -2^(format.exponentWidth() - 1) - 2 - (format.significandWidth() - 1) |
187 |
|
// |
188 |
|
// We need an unpacked exponent width u such that |
189 |
|
// -2^(u-1) <= -2^(format.exponentWidth() - 1) - 2 - (format.significandWidth() - 1) |
190 |
|
// i.e. |
191 |
|
// 2^(u-1) >= 2^(format.exponentWidth() - 1) + (format.significandWidth() - 3) |
192 |
|
|
193 |
364901 |
bwt formatExponentWidth = format.exponentWidth(); |
194 |
364901 |
bwt formatSignificandWidth = format.significandWidth(); |
195 |
|
|
196 |
364901 |
if (formatSignificandWidth <= 3) { |
197 |
|
// Subnormals fit into the gap between minimum normal exponent and what is represenatble |
198 |
|
// using a signed number |
199 |
1088 |
return formatExponentWidth; |
200 |
|
} |
201 |
|
|
202 |
363813 |
bwt bitsNeededForSubnormals = bitsToRepresent(format.significandWidth() - 3); |
203 |
363813 |
if (bitsNeededForSubnormals < formatExponentWidth - 1) { |
204 |
|
// Significand is short compared to exponent range, |
205 |
|
// one extra bit should be sufficient |
206 |
45470 |
return formatExponentWidth + 1; |
207 |
|
|
208 |
|
} else { |
209 |
|
// Significand is long compared to exponent range |
210 |
318343 |
return bitsToRepresent((bwt(1) << (formatExponentWidth - 1)) + formatSignificandWidth - 3) + 1; |
211 |
|
} |
212 |
|
} |
213 |
|
|
214 |
137009 |
static bwt significandWidth(const fpt &format) { |
215 |
|
// Hidden bit is already included in the floating-point format |
216 |
137009 |
return format.significandWidth(); |
217 |
|
} |
218 |
|
|
219 |
|
|
220 |
|
|
221 |
|
|
222 |
|
// These should all evaluate to a literal value but are given as |
223 |
|
// sbv's to make their use easier and to avoid concerns of overflow. |
224 |
|
|
225 |
187412 |
static sbv bias(const fpt &format) { |
226 |
187412 |
bwt w(exponentWidth(format)); |
227 |
374824 |
sbv one(sbv::one(w)); |
228 |
|
|
229 |
374824 |
return (one << sbv(w,(format.exponentWidth() - 1))) - one; |
230 |
|
} |
231 |
|
|
232 |
|
|
233 |
34082 |
static sbv maxNormalExponent(const fpt &format) { |
234 |
34082 |
return bias(format); |
235 |
|
} |
236 |
|
|
237 |
65304 |
static sbv minNormalExponent(const fpt &format) { |
238 |
65304 |
return -(bias(format) - sbv::one(exponentWidth(format))); |
239 |
|
} |
240 |
|
|
241 |
81374 |
static sbv maxSubnormalExponent(const fpt &format) { |
242 |
81374 |
return -bias(format); |
243 |
|
} |
244 |
|
|
245 |
54621 |
static sbv minSubnormalExponent(const fpt &format) { |
246 |
54621 |
return maxSubnormalExponent(format) - sbv(exponentWidth(format),(significandWidth(format) - 2)); |
247 |
|
} |
248 |
|
|
249 |
|
// Note the different return type as this is used for iteration in remainder |
250 |
119 |
static bwt maximumExponentDifference(const fpt &format) { |
251 |
119 |
bwt maxNormalExp = (1ULL << (format.exponentWidth() - 1)) - 1; |
252 |
119 |
bwt minSubnormalExp = -maxNormalExp - (significandWidth(format) - 2); |
253 |
119 |
return maxNormalExp - minSubnormalExp; |
254 |
|
} |
255 |
|
|
256 |
|
// knownInFormat uses the format invariant to simplify the test |
257 |
6343 |
inline prop inNormalRange(const fpt &format, const prop &knownInFormat) const { |
258 |
15613 |
return ((minNormalExponent(format) <= exponent) && |
259 |
15685 |
((exponent <= maxNormalExponent(format) || knownInFormat))); |
260 |
|
} |
261 |
|
|
262 |
|
// knownInFormat uses the format invariant to simplify the test |
263 |
26753 |
inline prop inSubnormalRange(const fpt &format, const prop &knownInFormat) const { |
264 |
|
// To share tests with the inNormalRange test... |
265 |
34821 |
prop upperBound(!(minNormalExponent(format) <= exponent)); |
266 |
26753 |
INVARIANT(upperBound == (exponent <= maxSubnormalExponent(format))); |
267 |
|
|
268 |
37370 |
return (((minSubnormalExponent(format) <= exponent) || knownInFormat) && |
269 |
53506 |
upperBound); |
270 |
|
} |
271 |
|
|
272 |
23446 |
inline prop inNormalOrSubnormalRange(const fpt &format, const prop &knownInFormat) const { |
273 |
92615 |
return ((minSubnormalExponent(format) <= exponent) && |
274 |
97538 |
(exponent <= maxNormalExponent(format))) || knownInFormat; |
275 |
|
} |
276 |
|
|
277 |
|
|
278 |
|
|
279 |
|
// The amount needed to normalise the number |
280 |
29754 |
inline sbv getSubnormalAmount(const fpt &format) const { |
281 |
|
return max<t>(minNormalExponent(format) - exponent, |
282 |
29754 |
sbv::zero(exponent.getWidth())); |
283 |
|
} |
284 |
|
|
285 |
323 |
inline prop isPositiveInf (void) const { |
286 |
323 |
return this->inf && !this->sign; |
287 |
|
} |
288 |
|
|
289 |
329 |
inline prop isNegativeInf (void) const { |
290 |
329 |
return this->inf && this->sign; |
291 |
|
} |
292 |
|
|
293 |
|
|
294 |
|
|
295 |
|
// Likewise, this is a convenience function |
296 |
26955 |
static ubv leadingOne(const bwt sigWidth) { |
297 |
26955 |
return ubv::one(sigWidth) << ubv(sigWidth, (sigWidth - 1)); |
298 |
|
} |
299 |
|
|
300 |
6308 |
static ubv nanPattern(const bwt sigWidth) { |
301 |
6308 |
return ubv::one(sigWidth) << ubv(sigWidth, (sigWidth - 1)); // For a qNaN, change for sNaN |
302 |
|
} |
303 |
|
|
304 |
|
|
305 |
|
|
306 |
125 |
unpackedFloat<t> extend (const bwt expExtension, const bwt sigExtension) const { |
307 |
|
return unpackedFloat<t>(this->nan, |
308 |
|
this->inf, |
309 |
|
this->zero, |
310 |
|
this->sign, |
311 |
|
this->exponent.extend(expExtension), |
312 |
125 |
this->significand.extend(sigExtension) << ubv((this->significand.getWidth() + sigExtension), sigExtension)); |
313 |
|
} |
314 |
|
|
315 |
|
|
316 |
|
// Moves the leading 1 up to the correct position, adjusting the |
317 |
|
// exponent as required. |
318 |
972 |
unpackedFloat<t> normaliseUp (const fpt &/*format*/) const { |
319 |
972 |
PRECONDITION(!(nan || inf || zero)); // Should not be attempting to normalise these. |
320 |
|
|
321 |
1944 |
normaliseShiftResult<t> normal(normaliseShift<t>(this->significand)); |
322 |
|
|
323 |
972 |
bwt exponentWidth(this->exponent.getWidth()); |
324 |
972 |
INVARIANT(normal.shiftAmount.getWidth() < exponentWidth); // May loose data / be incorrect for very small exponents and very large significands |
325 |
|
|
326 |
1944 |
sbv signedAlignAmount(normal.shiftAmount.resize(exponentWidth).toSigned()); |
327 |
1944 |
sbv correctedExponent(this->exponent - signedAlignAmount); |
328 |
|
|
329 |
|
// Optimisation : could move the zero detect version in if used in all cases |
330 |
|
// catch - it zero detection in unpacking is different. |
331 |
1944 |
return unpackedFloat<t>(this->sign, correctedExponent, normal.normalised); |
332 |
|
} |
333 |
|
|
334 |
|
|
335 |
195 |
unpackedFloat<t> normaliseUpDetectZero (const fpt &format) const { |
336 |
195 |
PRECONDITION(!(nan || inf || zero)); // Should not be attempting to normalise these. |
337 |
|
|
338 |
390 |
normaliseShiftResult<t> normal(normaliseShift<t>(this->significand)); |
339 |
|
|
340 |
195 |
bwt exponentWidth(this->exponent.getWidth()); |
341 |
195 |
INVARIANT(normal.shiftAmount.getWidth() < exponentWidth); // May loose data / be incorrect for very small exponents and very large significands |
342 |
|
|
343 |
390 |
sbv signedAlignAmount(normal.shiftAmount.resize(exponentWidth).toSigned()); |
344 |
390 |
sbv correctedExponent(this->exponent - signedAlignAmount); |
345 |
|
|
346 |
|
return ITE(normal.isZero, |
347 |
|
unpackedFloat<t>::makeZero(format, this->sign), |
348 |
390 |
unpackedFloat<t>(this->sign, correctedExponent, normal.normalised)); |
349 |
|
} |
350 |
|
|
351 |
|
#if 0 |
352 |
|
// Moves the leading 1 up to the correct position, adjusting the |
353 |
|
// exponent as required. |
354 |
|
unpackedFloat<t> normaliseUp (const fpt &/*format*/) const { |
355 |
|
PRECONDITION(!(nan || inf || zero)); // Should not be attempting to normalise these. |
356 |
|
|
357 |
|
ubv alignAmount(countLeadingZeros<t>(this->significand)); |
358 |
|
|
359 |
|
ubv alignedSignificand(this->significand.modularLeftShift(alignAmount)); // CLZ means data is not lost |
360 |
|
|
361 |
|
sbv signedAlignAmount(alignAmount.extract(this->exponent.getWidth() - 1,0).toSigned()); |
362 |
|
// May loose data / be incorrect for very small exponents and very large significands |
363 |
|
sbv correctedExponent(this->exponent - signedAlignAmount); |
364 |
|
|
365 |
|
// Optimisation : could move the zero detect version in if used in all cases |
366 |
|
return unpackedFloat<t>(this->sign, correctedExponent, alignedSignificand); |
367 |
|
} |
368 |
|
|
369 |
|
unpackedFloat<t> normaliseUpDetectZero (const fpt &format) const { |
370 |
|
unpackedFloat<t> normal(this->normaliseUp(format)); |
371 |
|
|
372 |
|
return ITE(this->significand.isAllZeros(), |
373 |
|
unpackedFloat<t>::makeZero(format, this->sign), |
374 |
|
normal); |
375 |
|
} |
376 |
|
#endif |
377 |
|
|
378 |
|
|
379 |
|
#if 0 |
380 |
|
unpackedFloat<t> normaliseUp (const fpt &format) const { |
381 |
|
PRECONDITION(!(nan || inf || zero)); // Should not be attempting to normalise these. |
382 |
|
|
383 |
|
unpackedFloat<t> working(*this); |
384 |
|
bwt sigWidth = unpackedFloat<t>::significandWidth(format); |
385 |
|
bwt exWidth = unpackedFloat<t>::exponentWidth(format); |
386 |
|
|
387 |
|
// TODO : is range checking needed here? Only in obscure use cases. |
388 |
|
|
389 |
|
for (bwt power = previousPowerOfTwo(sigWidth); power != 0; power >>= 1) { |
390 |
|
bwt rem = sigWidth - power; |
391 |
|
|
392 |
|
INVARIANT(rem > 0); |
393 |
|
|
394 |
|
ubv mask(ubv::allOnes(power).extend(rem) << rem); |
395 |
|
prop shiftNeeded((mask & working.significand).isAllZeros()); |
396 |
|
|
397 |
|
// Has to be modular as in the case it is not needed, |
398 |
|
// performing the shift will loose information. |
399 |
|
working.significand = ITE(shiftNeeded, working.significand.modularLeftShift(power), working.significand); |
400 |
|
working.exponent = ITE(shiftNeeded, working.exponent - sbv(exWidth,power), working.exponent); |
401 |
|
// Optimisation : rather than add each cycle, build shiftNeeded into a number and add once. |
402 |
|
} |
403 |
|
|
404 |
|
return working; |
405 |
|
} |
406 |
|
#endif |
407 |
|
|
408 |
|
|
409 |
|
|
410 |
|
// Is a well formed unpacked struct of the given format? |
411 |
|
// The format is needed to ensure that subnormals are correct. |
412 |
|
// This invariant does not hold at all points in the code! |
413 |
23446 |
prop valid(const fpt &format) const { |
414 |
|
|
415 |
23446 |
bwt exWidth = exponentWidth(format); |
416 |
23446 |
bwt sigWidth = significandWidth(format); |
417 |
|
|
418 |
23446 |
PRECONDITION((exWidth == exponent.getWidth()) && |
419 |
|
(sigWidth == significand.getWidth())); |
420 |
|
|
421 |
|
// At most one flag is true |
422 |
28369 |
prop atMostOneFlag(!(nan && inf) && !(nan && zero) && !(inf && zero)); |
423 |
|
|
424 |
|
// If one flag is true then exponent and significand are defaults |
425 |
28369 |
prop oneFlag(nan || inf || zero); |
426 |
28369 |
prop exponentIsDefault(defaultExponent(format) == exponent); |
427 |
28369 |
prop significandIsDefault(defaultSignificand(format) == significand); |
428 |
28369 |
prop flagImpliesDefaultExponent(IMPLIES(oneFlag, exponentIsDefault)); |
429 |
28369 |
prop flagImpliesDefaultSignificand(IMPLIES(oneFlag, significandIsDefault)); |
430 |
|
|
431 |
|
// NaN has sign = 0 |
432 |
28369 |
prop NaNImpliesSignFalse(IMPLIES(nan, !sign)); |
433 |
|
|
434 |
|
// Exponent is in range |
435 |
28369 |
prop exponentInRange(inNormalOrSubnormalRange(format, prop(false))); |
436 |
|
|
437 |
|
// Has a leading one |
438 |
28369 |
prop hasLeadingOne(!(leadingOne(unpackedFloat<t>::significandWidth(format)) & significand).isAllZeros()); |
439 |
|
|
440 |
|
// Subnormal numbers require an additional check to make sure they |
441 |
|
// do not have an unrepresentable amount of significand bits. |
442 |
46892 |
sbv subnormalAmount(this->getSubnormalAmount(format)); |
443 |
23446 |
INVARIANT((sbv::zero(exWidth) <= subnormalAmount) && |
444 |
|
(subnormalAmount <= sbv(exWidth,sigWidth))); |
445 |
|
|
446 |
|
// Invariant implies this following steps do not loose data |
447 |
46892 |
ubv mask(orderEncode<t>((sigWidth >= exWidth) ? |
448 |
|
subnormalAmount.toUnsigned().matchWidth(significand) : |
449 |
|
subnormalAmount.toUnsigned().extract(sigWidth - 1, 0) |
450 |
|
)); |
451 |
|
|
452 |
28369 |
prop correctlyAbbreviated((mask & significand).isAllZeros()); |
453 |
|
|
454 |
28369 |
prop subnormalImpliesTrailingZeros(IMPLIES(inSubnormalRange(format, prop(false)), correctlyAbbreviated)); |
455 |
|
|
456 |
|
|
457 |
18523 |
return (atMostOneFlag && |
458 |
18523 |
(flagImpliesDefaultExponent && flagImpliesDefaultSignificand) && |
459 |
18523 |
NaNImpliesSignFalse && |
460 |
18523 |
exponentInRange && |
461 |
37046 |
hasLeadingOne && |
462 |
46892 |
subnormalImpliesTrailingZeros); |
463 |
|
} |
464 |
|
|
465 |
|
|
466 |
|
|
467 |
|
/* Older version |
468 |
|
* Correct but replaced with a version which gives more propagation friendly assertions. |
469 |
|
*/ |
470 |
|
#if 0 |
471 |
|
prop valid(const fpt &format) const { |
472 |
|
|
473 |
|
bwt exWidth = exponentWidth(format); |
474 |
|
bwt sigWidth = significandWidth(format); |
475 |
|
|
476 |
|
PRECONDITION((exWidth == exponent.getWidth()) && |
477 |
|
(sigWidth == significand.getWidth())); |
478 |
|
|
479 |
|
prop hasLeadingOne(!(leadingOne(unpackedFloat<t>::significandWidth(format)) & significand).isAllZeros()); |
480 |
|
|
481 |
|
|
482 |
|
|
483 |
|
// Subnormal numbers require an additional check to make sure they |
484 |
|
// do not have an unrepresentable amount of significand bits. |
485 |
|
sbv subnormalAmount(this->getSubnormalAmount(format)); |
486 |
|
INVARIANT((sbv::zero(exWidth) <= subnormalAmount) && |
487 |
|
(subnormalAmount <= sbv(exWidth,sigWidth))); |
488 |
|
|
489 |
|
// Invariant implies this following steps do not loose data |
490 |
|
ubv trimmedSubnormalAmount(subnormalAmount.toUnsigned().extract(positionOfLeadingOne(sigWidth),0)); |
491 |
|
ubv mask(trimmedSubnormalAmount.orderEncode(sigWidth)); |
492 |
|
|
493 |
|
prop correctlyAbbreviated((mask & significand).isAllZeros()); |
494 |
|
|
495 |
|
|
496 |
|
|
497 |
|
prop normalCase (!nan && !inf && !zero && inNormalRange(format, prop(false)) && hasLeadingOne); |
498 |
|
prop subnormalCase(!nan && !inf && !zero && inSubnormalRange(format, prop(false)) && hasLeadingOne && correctlyAbbreviated); |
499 |
|
|
500 |
|
|
501 |
|
|
502 |
|
prop exponentIsDefault(defaultExponent(format) == exponent); |
503 |
|
prop significandIsDefault(defaultSignificand(format) == significand); |
504 |
|
|
505 |
|
prop NaNCase ( nan && !inf && !zero && exponentIsDefault && significandIsDefault && !sign); |
506 |
|
prop InfCase (!nan && inf && !zero && exponentIsDefault && significandIsDefault); |
507 |
|
prop ZeroCase(!nan && !inf && zero && exponentIsDefault && significandIsDefault); |
508 |
|
|
509 |
|
return (NaNCase || InfCase || ZeroCase || normalCase || subnormalCase); |
510 |
|
|
511 |
|
} |
512 |
|
#endif |
513 |
|
|
514 |
|
|
515 |
|
// Just for debugging |
516 |
|
void print (void) const { |
517 |
|
std::cerr << "nan : " << this->nan << '\t' |
518 |
|
<< "inf : " << this->inf << '\t' |
519 |
|
<< "zero : " << this->zero << '\t' |
520 |
|
<< "sign : " << this->sign << '\t' |
521 |
|
<< "exponent : " << this->exponent << '\t' |
522 |
|
<< "significand : " << this->significand << std::endl; |
523 |
|
} |
524 |
|
|
525 |
|
}; |
526 |
|
|
527 |
|
template <class t> |
528 |
|
struct ite<typename t::prop, unpackedFloat<t> > { |
529 |
14163 |
static const unpackedFloat<t> iteOp (const typename t::prop &cond, |
530 |
|
const unpackedFloat<t> &l, |
531 |
|
const unpackedFloat<t> &r) { |
532 |
26756 |
return unpackedFloat<t>(ITE(cond, l.nan, r.nan), |
533 |
26756 |
ITE(cond, l.inf, r.inf), |
534 |
26756 |
ITE(cond, l.zero, r.zero), |
535 |
26756 |
ITE(cond, l.sign, r.sign), |
536 |
|
ITE(cond, l.exponent, r.exponent), |
537 |
40919 |
ITE(cond, l.significand, r.significand)); |
538 |
|
} |
539 |
|
}; |
540 |
|
|
541 |
|
|
542 |
|
|
543 |
|
|
544 |
|
} |
545 |
|
|
546 |
|
#endif |