1///////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
4// Digital Ltd. LLC
5//
6// All rights reserved.
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11// *       Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// *       Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17// *       Neither the name of Industrial Light & Magic nor the names of
18// its contributors may be used to endorse or promote products derived
19// from this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32//
33///////////////////////////////////////////////////////////////////////////
34
35// Primary authors:
36//     Florian Kainz <kainz@ilm.com>
37//     Rod Bogart <rgb@ilm.com>
38
39
40//---------------------------------------------------------------------------
41//
42//	class half --
43//	implementation of non-inline members
44//
45//---------------------------------------------------------------------------
46
47#include <assert.h>
48#include "half.h"
49
50using namespace std;
51
52//-------------------------------------------------------------
53// Lookup tables for half-to-float and float-to-half conversion
54//-------------------------------------------------------------
55
56#if defined (OPENEXR_DLL)
57__declspec(dllexport) half::uif _toFloat[1 << 16] =
58    #include "toFloat.h"
59__declspec(dllexport) unsigned short _eLut[1 << 9] =
60    #include "eLut.h"
61#else
62const half::uif half::_toFloat[1 << 16] =
63    #include "toFloat.h"
64const unsigned short half::_eLut[1 << 9] =
65    #include "eLut.h"
66#endif
67
68//-----------------------------------------------
69// Overflow handler for float-to-half conversion;
70// generates a hardware floating-point overflow,
71// which may be trapped by the operating system.
72//-----------------------------------------------
73
74float
75half::overflow ()
76{
77    volatile float f = 1e10;
78
79    for (int i = 0; i < 10; i++)
80	f *= f;				// this will overflow before
81					// the for�loop terminates
82    return f;
83}
84
85
86//-----------------------------------------------------
87// Float-to-half conversion -- general case, including
88// zeroes, denormalized numbers and exponent overflows.
89//-----------------------------------------------------
90
91short
92half::convert (int i)
93{
94    //
95    // Our floating point number, f, is represented by the bit
96    // pattern in integer i.  Disassemble that bit pattern into
97    // the sign, s, the exponent, e, and the significand, m.
98    // Shift s into the position where it will go in in the
99    // resulting half number.
100    // Adjust e, accounting for the different exponent bias
101    // of float and half (127 versus 15).
102    //
103
104    register int s =  (i >> 16) & 0x00008000;
105    register int e = ((i >> 23) & 0x000000ff) - (127 - 15);
106    register int m =   i        & 0x007fffff;
107
108    //
109    // Now reassemble s, e and m into a half:
110    //
111
112    if (e <= 0)
113    {
114	if (e < -10)
115	{
116	    //
117	    // E is less than -10.  The absolute value of f is
118	    // less than HALF_MIN (f may be a small normalized
119	    // float, a denormalized float or a zero).
120	    //
121	    // We convert f to a half zero with the same sign as f.
122	    //
123
124	    return s;
125	}
126
127	//
128	// E is between -10 and 0.  F is a normalized float
129	// whose magnitude is less than HALF_NRM_MIN.
130	//
131	// We convert f to a denormalized half.
132	//
133
134	//
135	// Add an explicit leading 1 to the significand.
136	//
137
138	m = m | 0x00800000;
139
140	//
141	// Round to m to the nearest (10+e)-bit value (with e between
142	// -10 and 0); in case of a tie, round to the nearest even value.
143	//
144	// Rounding may cause the significand to overflow and make
145	// our number normalized.  Because of the way a half's bits
146	// are laid out, we don't have to treat this case separately;
147	// the code below will handle it correctly.
148	//
149
150	int t = 14 - e;
151	int a = (1 << (t - 1)) - 1;
152	int b = (m >> t) & 1;
153
154	m = (m + a + b) >> t;
155
156	//
157	// Assemble the half from s, e (zero) and m.
158	//
159
160	return s | m;
161    }
162    else if (e == 0xff - (127 - 15))
163    {
164	if (m == 0)
165	{
166	    //
167	    // F is an infinity; convert f to a half
168	    // infinity with the same sign as f.
169	    //
170
171	    return s | 0x7c00;
172	}
173	else
174	{
175	    //
176	    // F is a NAN; we produce a half NAN that preserves
177	    // the sign bit and the 10 leftmost bits of the
178	    // significand of f, with one exception: If the 10
179	    // leftmost bits are all zero, the NAN would turn
180	    // into an infinity, so we have to set at least one
181	    // bit in the significand.
182	    //
183
184	    m >>= 13;
185	    return s | 0x7c00 | m | (m == 0);
186	}
187    }
188    else
189    {
190	//
191	// E is greater than zero.  F is a normalized float.
192	// We try to convert f to a normalized half.
193	//
194
195	//
196	// Round to m to the nearest 10-bit value.  In case of
197	// a tie, round to the nearest even value.
198	//
199
200	m = m + 0x00000fff + ((m >> 13) & 1);
201
202	if (m & 0x00800000)
203	{
204	    m =  0;		// overflow in significand,
205	    e += 1;		// adjust exponent
206	}
207
208	//
209	// Handle exponent overflow
210	//
211
212	if (e > 30)
213	{
214	    overflow ();	// Cause a hardware floating point overflow;
215	    return s | 0x7c00;	// if this returns, the half becomes an
216	}   			// infinity with the same sign as f.
217
218	//
219	// Assemble the half from s, e and m.
220	//
221
222	return s | (e << 10) | (m >> 13);
223    }
224}
225
226
227//---------------------
228// Stream I/O operators
229//---------------------
230
231ostream &
232operator << (ostream &os, half h)
233{
234    os << float (h);
235    return os;
236}
237
238
239istream &
240operator >> (istream &is, half &h)
241{
242    float f;
243    is >> f;
244    h = half (f);
245    return is;
246}
247
248
249//---------------------------------------
250// Functions to print the bit-layout of
251// floats and halfs, mostly for debugging
252//---------------------------------------
253
254void
255printBits (ostream &os, half h)
256{
257    unsigned short b = h.bits();
258
259    for (int i = 15; i >= 0; i--)
260    {
261	os << (((b >> i) & 1)? '1': '0');
262
263	if (i == 15 || i == 10)
264	    os << ' ';
265    }
266}
267
268
269void
270printBits (ostream &os, float f)
271{
272    half::uif x;
273    x.f = f;
274
275    for (int i = 31; i >= 0; i--)
276    {
277	os << (((x.i >> i) & 1)? '1': '0');
278
279	if (i == 31 || i == 23)
280	    os << ' ';
281    }
282}
283
284
285void
286printBits (char c[19], half h)
287{
288    unsigned short b = h.bits();
289
290    for (int i = 15, j = 0; i >= 0; i--, j++)
291    {
292	c[j] = (((b >> i) & 1)? '1': '0');
293
294	if (i == 15 || i == 10)
295	    c[++j] = ' ';
296    }
297
298    c[18] = 0;
299}
300
301
302void
303printBits (char c[35], float f)
304{
305    half::uif x;
306    x.f = f;
307
308    for (int i = 31, j = 0; i >= 0; i--, j++)
309    {
310	c[j] = (((x.i >> i) & 1)? '1': '0');
311
312	if (i == 31 || i == 23)
313	    c[++j] = ' ';
314    }
315
316    c[34] = 0;
317}
318