• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/// @ref core
2/// @file glm/detail/type_half.inl
3
4namespace glm{
5namespace detail
6{
7	GLM_FUNC_QUALIFIER float overflow()
8	{
9		volatile float f = 1e10;
10
11		for(int i = 0; i < 10; ++i)
12			f *= f; // this will overflow before the for loop terminates
13		return f;
14	}
15
16	union uif32
17	{
18		GLM_FUNC_QUALIFIER uif32() :
19			i(0)
20		{}
21
22		GLM_FUNC_QUALIFIER uif32(float f_) :
23			f(f_)
24		{}
25
26		GLM_FUNC_QUALIFIER uif32(uint32 i_) :
27			i(i_)
28		{}
29
30		float f;
31		uint32 i;
32	};
33
34	GLM_FUNC_QUALIFIER float toFloat32(hdata value)
35	{
36		int s = (value >> 15) & 0x00000001;
37		int e = (value >> 10) & 0x0000001f;
38		int m =  value        & 0x000003ff;
39
40		if(e == 0)
41		{
42			if(m == 0)
43			{
44				//
45				// Plus or minus zero
46				//
47
48				detail::uif32 result;
49				result.i = (unsigned int)(s << 31);
50				return result.f;
51			}
52			else
53			{
54				//
55				// Denormalized number -- renormalize it
56				//
57
58				while(!(m & 0x00000400))
59				{
60					m <<= 1;
61					e -=  1;
62				}
63
64				e += 1;
65				m &= ~0x00000400;
66			}
67		}
68		else if(e == 31)
69		{
70			if(m == 0)
71			{
72				//
73				// Positive or negative infinity
74				//
75
76				uif32 result;
77				result.i = (unsigned int)((s << 31) | 0x7f800000);
78				return result.f;
79			}
80			else
81			{
82				//
83				// Nan -- preserve sign and significand bits
84				//
85
86				uif32 result;
87				result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13));
88				return result.f;
89			}
90		}
91
92		//
93		// Normalized number
94		//
95
96		e = e + (127 - 15);
97		m = m << 13;
98
99		//
100		// Assemble s, e and m.
101		//
102
103		uif32 Result;
104		Result.i = (unsigned int)((s << 31) | (e << 23) | m);
105		return Result.f;
106	}
107
108	GLM_FUNC_QUALIFIER hdata toFloat16(float const & f)
109	{
110		uif32 Entry;
111		Entry.f = f;
112		int i = (int)Entry.i;
113
114		//
115		// Our floating point number, f, is represented by the bit
116		// pattern in integer i.  Disassemble that bit pattern into
117		// the sign, s, the exponent, e, and the significand, m.
118		// Shift s into the position where it will go in in the
119		// resulting half number.
120		// Adjust e, accounting for the different exponent bias
121		// of float and half (127 versus 15).
122		//
123
124		int s =  (i >> 16) & 0x00008000;
125		int e = ((i >> 23) & 0x000000ff) - (127 - 15);
126		int m =   i        & 0x007fffff;
127
128		//
129		// Now reassemble s, e and m into a half:
130		//
131
132		if(e <= 0)
133		{
134			if(e < -10)
135			{
136				//
137				// E is less than -10.  The absolute value of f is
138				// less than half_MIN (f may be a small normalized
139				// float, a denormalized float or a zero).
140				//
141				// We convert f to a half zero.
142				//
143
144				return hdata(s);
145			}
146
147			//
148			// E is between -10 and 0.  F is a normalized float,
149			// whose magnitude is less than __half_NRM_MIN.
150			//
151			// We convert f to a denormalized half.
152			//
153
154			m = (m | 0x00800000) >> (1 - e);
155
156			//
157			// Round to nearest, round "0.5" up.
158			//
159			// Rounding may cause the significand to overflow and make
160			// our number normalized.  Because of the way a half's bits
161			// are laid out, we don't have to treat this case separately;
162			// the code below will handle it correctly.
163			//
164
165			if(m & 0x00001000)
166				m += 0x00002000;
167
168			//
169			// Assemble the half from s, e (zero) and m.
170			//
171
172			return hdata(s | (m >> 13));
173		}
174		else if(e == 0xff - (127 - 15))
175		{
176			if(m == 0)
177			{
178				//
179				// F is an infinity; convert f to a half
180				// infinity with the same sign as f.
181				//
182
183				return hdata(s | 0x7c00);
184			}
185			else
186			{
187				//
188				// F is a NAN; we produce a half NAN that preserves
189				// the sign bit and the 10 leftmost bits of the
190				// significand of f, with one exception: If the 10
191				// leftmost bits are all zero, the NAN would turn
192				// into an infinity, so we have to set at least one
193				// bit in the significand.
194				//
195
196				m >>= 13;
197
198				return hdata(s | 0x7c00 | m | (m == 0));
199			}
200		}
201		else
202		{
203			//
204			// E is greater than zero.  F is a normalized float.
205			// We try to convert f to a normalized half.
206			//
207
208			//
209			// Round to nearest, round "0.5" up
210			//
211
212			if(m &  0x00001000)
213			{
214				m += 0x00002000;
215
216				if(m & 0x00800000)
217				{
218					m =  0;     // overflow in significand,
219					e += 1;     // adjust exponent
220				}
221			}
222
223			//
224			// Handle exponent overflow
225			//
226
227			if (e > 30)
228			{
229				overflow();        // Cause a hardware floating point overflow;
230
231				return hdata(s | 0x7c00);
232				// if this returns, the half becomes an
233			}   // infinity with the same sign as f.
234
235			//
236			// Assemble the half from s, e and m.
237			//
238
239			return hdata(s | (e << 10) | (m >> 13));
240		}
241	}
242
243}//namespace detail
244}//namespace glm
245