xref: /openbsd-src/sys/lib/libkern/softfloat-specialize.h (revision d874cce4b1d9fe6b41c9e4f2117a77d8a4a37b92)
1*d874cce4Sray /*	$OpenBSD: softfloat-specialize.h,v 1.3 2008/06/26 05:42:20 ray Exp $	*/
2433075b6Spvalchev /*	$NetBSD: softfloat-specialize.h,v 1.1 2001/04/26 03:10:47 ross Exp $	*/
3433075b6Spvalchev 
4433075b6Spvalchev /* This is a derivative work. */
5433075b6Spvalchev 
6433075b6Spvalchev /*-
7433075b6Spvalchev  * Copyright (c) 2001 The NetBSD Foundation, Inc.
8433075b6Spvalchev  * All rights reserved.
9433075b6Spvalchev  *
10433075b6Spvalchev  * This code is derived from software contributed to The NetBSD Foundation
11433075b6Spvalchev  * by Ross Harvey.
12433075b6Spvalchev  *
13433075b6Spvalchev  * Redistribution and use in source and binary forms, with or without
14433075b6Spvalchev  * modification, are permitted provided that the following conditions
15433075b6Spvalchev  * are met:
16433075b6Spvalchev  * 1. Redistributions of source code must retain the above copyright
17433075b6Spvalchev  *    notice, this list of conditions and the following disclaimer.
18433075b6Spvalchev  * 2. Redistributions in binary form must reproduce the above copyright
19433075b6Spvalchev  *    notice, this list of conditions and the following disclaimer in the
20433075b6Spvalchev  *    documentation and/or other materials provided with the distribution.
21433075b6Spvalchev  *
22433075b6Spvalchev  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23433075b6Spvalchev  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24433075b6Spvalchev  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25433075b6Spvalchev  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26433075b6Spvalchev  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27433075b6Spvalchev  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28433075b6Spvalchev  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29433075b6Spvalchev  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30433075b6Spvalchev  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31433075b6Spvalchev  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32433075b6Spvalchev  * POSSIBILITY OF SUCH DAMAGE.
33433075b6Spvalchev  */
34433075b6Spvalchev 
35433075b6Spvalchev /*
36433075b6Spvalchev ===============================================================================
37433075b6Spvalchev 
38433075b6Spvalchev This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
39433075b6Spvalchev Arithmetic Package, Release 2a.
40433075b6Spvalchev 
41433075b6Spvalchev Written by John R. Hauser.  This work was made possible in part by the
42433075b6Spvalchev International Computer Science Institute, located at Suite 600, 1947 Center
43433075b6Spvalchev Street, Berkeley, California 94704.  Funding was partially provided by the
44433075b6Spvalchev National Science Foundation under grant MIP-9311980.  The original version
45433075b6Spvalchev of this code was written as part of a project to build a fixed-point vector
46433075b6Spvalchev processor in collaboration with the University of California at Berkeley,
47433075b6Spvalchev overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
48433075b6Spvalchev is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
49433075b6Spvalchev arithmetic/SoftFloat.html'.
50433075b6Spvalchev 
51433075b6Spvalchev THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable
52433075b6Spvalchev effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT
53433075b6Spvalchev WILL AT TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS
54433075b6Spvalchev RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL
55433075b6Spvalchev RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM
56433075b6Spvalchev THEIR OWN USE OF THE SOFTWARE, AND WHO ALSO EFFECTIVELY INDEMNIFY
57433075b6Spvalchev (possibly via similar legal warning) JOHN HAUSER AND THE INTERNATIONAL
58433075b6Spvalchev COMPUTER SCIENCE INSTITUTE AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS
59433075b6Spvalchev ARISING FROM THE USE OF THE SOFTWARE BY THEIR CUSTOMERS AND CLIENTS.
60433075b6Spvalchev 
61433075b6Spvalchev Derivative works are acceptable, even for commercial purposes, so long as
62433075b6Spvalchev (1) they include prominent notice that the work is derivative, and (2) they
63433075b6Spvalchev include prominent notice akin to these four paragraphs for those parts of
64433075b6Spvalchev this code that are retained.
65433075b6Spvalchev 
66433075b6Spvalchev ===============================================================================
67433075b6Spvalchev */
68433075b6Spvalchev 
69433075b6Spvalchev /*
70433075b6Spvalchev -------------------------------------------------------------------------------
71433075b6Spvalchev Underflow tininess-detection mode, statically initialized to default value.
72433075b6Spvalchev -------------------------------------------------------------------------------
73433075b6Spvalchev */
74433075b6Spvalchev 
75433075b6Spvalchev /* [ MP safe, does not change dynamically ] */
76433075b6Spvalchev int float_detect_tininess = float_tininess_after_rounding;
77433075b6Spvalchev 
78433075b6Spvalchev /*
79433075b6Spvalchev -------------------------------------------------------------------------------
80433075b6Spvalchev Internal canonical NaN format.
81433075b6Spvalchev -------------------------------------------------------------------------------
82433075b6Spvalchev */
83433075b6Spvalchev typedef struct {
84433075b6Spvalchev     flag sign;
85433075b6Spvalchev     bits64 high, low;
86433075b6Spvalchev } commonNaNT;
87433075b6Spvalchev 
88433075b6Spvalchev /*
89433075b6Spvalchev -------------------------------------------------------------------------------
90433075b6Spvalchev The pattern for a default generated single-precision NaN.
91433075b6Spvalchev -------------------------------------------------------------------------------
92433075b6Spvalchev */
93433075b6Spvalchev #define float32_default_nan 0xFFC00000
94433075b6Spvalchev 
95433075b6Spvalchev /*
96433075b6Spvalchev -------------------------------------------------------------------------------
97433075b6Spvalchev Returns 1 if the single-precision floating-point value `a' is a NaN;
98433075b6Spvalchev otherwise returns 0.
99433075b6Spvalchev -------------------------------------------------------------------------------
100433075b6Spvalchev */
float32_is_nan(float32 a)101433075b6Spvalchev static flag float32_is_nan( float32 a )
102433075b6Spvalchev {
103433075b6Spvalchev 
104433075b6Spvalchev     return ( 0xFF000000 < (bits32) ( a<<1 ) );
105433075b6Spvalchev 
106433075b6Spvalchev }
107433075b6Spvalchev 
108433075b6Spvalchev /*
109433075b6Spvalchev -------------------------------------------------------------------------------
110433075b6Spvalchev Returns 1 if the single-precision floating-point value `a' is a signaling
111433075b6Spvalchev NaN; otherwise returns 0.
112433075b6Spvalchev -------------------------------------------------------------------------------
113433075b6Spvalchev */
float32_is_signaling_nan(float32 a)114433075b6Spvalchev flag float32_is_signaling_nan( float32 a )
115433075b6Spvalchev {
116433075b6Spvalchev 
117433075b6Spvalchev     return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
118433075b6Spvalchev 
119433075b6Spvalchev }
120433075b6Spvalchev 
121433075b6Spvalchev /*
122433075b6Spvalchev -------------------------------------------------------------------------------
123433075b6Spvalchev Returns the result of converting the single-precision floating-point NaN
124433075b6Spvalchev `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
125433075b6Spvalchev exception is raised.
126433075b6Spvalchev -------------------------------------------------------------------------------
127433075b6Spvalchev */
float32ToCommonNaN(float32 a)128433075b6Spvalchev static commonNaNT float32ToCommonNaN( float32 a )
129433075b6Spvalchev {
130433075b6Spvalchev     commonNaNT z;
131433075b6Spvalchev 
132433075b6Spvalchev     if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
133433075b6Spvalchev     z.sign = a>>31;
134433075b6Spvalchev     z.low = 0;
135433075b6Spvalchev     z.high = ( (bits64) a )<<41;
136433075b6Spvalchev     return z;
137433075b6Spvalchev 
138433075b6Spvalchev }
139433075b6Spvalchev 
140433075b6Spvalchev /*
141433075b6Spvalchev -------------------------------------------------------------------------------
142433075b6Spvalchev Returns the result of converting the canonical NaN `a' to the single-
143433075b6Spvalchev precision floating-point format.
144433075b6Spvalchev -------------------------------------------------------------------------------
145433075b6Spvalchev */
commonNaNToFloat32(commonNaNT a)146433075b6Spvalchev static float32 commonNaNToFloat32( commonNaNT a )
147433075b6Spvalchev {
148433075b6Spvalchev 
149433075b6Spvalchev     return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
150433075b6Spvalchev 
151433075b6Spvalchev }
152433075b6Spvalchev 
153433075b6Spvalchev /*
154433075b6Spvalchev -------------------------------------------------------------------------------
155433075b6Spvalchev Takes two single-precision floating-point values `a' and `b', one of which
156433075b6Spvalchev is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
157433075b6Spvalchev signaling NaN, the invalid exception is raised.
158433075b6Spvalchev -------------------------------------------------------------------------------
159433075b6Spvalchev */
propagateFloat32NaN(float32 a,float32 b)160433075b6Spvalchev static float32 propagateFloat32NaN( float32 a, float32 b )
161433075b6Spvalchev {
162433075b6Spvalchev     flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
163433075b6Spvalchev 
164433075b6Spvalchev     aIsNaN = float32_is_nan( a );
165433075b6Spvalchev     aIsSignalingNaN = float32_is_signaling_nan( a );
166433075b6Spvalchev     bIsNaN = float32_is_nan( b );
167433075b6Spvalchev     bIsSignalingNaN = float32_is_signaling_nan( b );
168433075b6Spvalchev     a |= 0x00400000;
169433075b6Spvalchev     b |= 0x00400000;
170433075b6Spvalchev     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
171433075b6Spvalchev     if ( aIsSignalingNaN ) {
172433075b6Spvalchev         if ( bIsSignalingNaN ) goto returnLargerSignificand;
173433075b6Spvalchev         return bIsNaN ? b : a;
174433075b6Spvalchev     }
175433075b6Spvalchev     else if ( aIsNaN ) {
176433075b6Spvalchev         if ( bIsSignalingNaN | ! bIsNaN ) return a;
177433075b6Spvalchev  returnLargerSignificand:
178433075b6Spvalchev         if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b;
179433075b6Spvalchev         if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a;
180433075b6Spvalchev         return ( a < b ) ? a : b;
181433075b6Spvalchev     }
182433075b6Spvalchev     else {
183433075b6Spvalchev         return b;
184433075b6Spvalchev     }
185433075b6Spvalchev 
186433075b6Spvalchev }
187433075b6Spvalchev 
188433075b6Spvalchev 
189433075b6Spvalchev /*
190433075b6Spvalchev -------------------------------------------------------------------------------
191433075b6Spvalchev Returns the result of converting the double-precision floating-point NaN
192433075b6Spvalchev `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
193433075b6Spvalchev exception is raised.
194433075b6Spvalchev -------------------------------------------------------------------------------
195433075b6Spvalchev */
float64ToCommonNaN(float64 a)196433075b6Spvalchev static commonNaNT float64ToCommonNaN( float64 a )
197433075b6Spvalchev {
198433075b6Spvalchev     commonNaNT z;
199433075b6Spvalchev 
200433075b6Spvalchev     if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
201433075b6Spvalchev     z.sign = a>>63;
202433075b6Spvalchev     z.low = 0;
203433075b6Spvalchev     z.high = a<<12;
204433075b6Spvalchev     return z;
205433075b6Spvalchev 
206433075b6Spvalchev }
207433075b6Spvalchev 
208433075b6Spvalchev /*
209433075b6Spvalchev -------------------------------------------------------------------------------
210433075b6Spvalchev Returns the result of converting the canonical NaN `a' to the double-
211433075b6Spvalchev precision floating-point format.
212433075b6Spvalchev -------------------------------------------------------------------------------
213433075b6Spvalchev */
commonNaNToFloat64(commonNaNT a)214433075b6Spvalchev static float64 commonNaNToFloat64( commonNaNT a )
215433075b6Spvalchev {
216433075b6Spvalchev 
217433075b6Spvalchev     return
218433075b6Spvalchev           ( ( (bits64) a.sign )<<63 )
219433075b6Spvalchev         | LIT64( 0x7FF8000000000000 )
220433075b6Spvalchev         | ( a.high>>12 );
221433075b6Spvalchev 
222433075b6Spvalchev }
223433075b6Spvalchev 
224433075b6Spvalchev /*
225433075b6Spvalchev -------------------------------------------------------------------------------
226433075b6Spvalchev Takes two double-precision floating-point values `a' and `b', one of which
227433075b6Spvalchev is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
228433075b6Spvalchev signaling NaN, the invalid exception is raised.
229433075b6Spvalchev -------------------------------------------------------------------------------
230433075b6Spvalchev */
propagateFloat64NaN(float64 a,float64 b)231433075b6Spvalchev static float64 propagateFloat64NaN( float64 a, float64 b )
232433075b6Spvalchev {
233433075b6Spvalchev     flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
234433075b6Spvalchev 
235433075b6Spvalchev     aIsNaN = float64_is_nan( a );
236433075b6Spvalchev     aIsSignalingNaN = float64_is_signaling_nan( a );
237433075b6Spvalchev     bIsNaN = float64_is_nan( b );
238433075b6Spvalchev     bIsSignalingNaN = float64_is_signaling_nan( b );
239433075b6Spvalchev     a |= LIT64( 0x0008000000000000 );
240433075b6Spvalchev     b |= LIT64( 0x0008000000000000 );
241433075b6Spvalchev     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
242433075b6Spvalchev     if ( aIsSignalingNaN ) {
243433075b6Spvalchev         if ( bIsSignalingNaN ) goto returnLargerSignificand;
244433075b6Spvalchev         return bIsNaN ? b : a;
245433075b6Spvalchev     }
246433075b6Spvalchev     else if ( aIsNaN ) {
247433075b6Spvalchev         if ( bIsSignalingNaN | ! bIsNaN ) return a;
248433075b6Spvalchev  returnLargerSignificand:
249433075b6Spvalchev         if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b;
250433075b6Spvalchev         if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a;
251433075b6Spvalchev         return ( a < b ) ? a : b;
252433075b6Spvalchev     }
253433075b6Spvalchev     else {
254433075b6Spvalchev         return b;
255433075b6Spvalchev     }
256433075b6Spvalchev 
257433075b6Spvalchev }
258433075b6Spvalchev 
259433075b6Spvalchev #ifdef FLOATX80
260433075b6Spvalchev 
261433075b6Spvalchev /*
262433075b6Spvalchev -------------------------------------------------------------------------------
263433075b6Spvalchev The pattern for a default generated extended double-precision NaN.  The
264433075b6Spvalchev `high' and `low' values hold the most- and least-significant bits,
265433075b6Spvalchev respectively.
266433075b6Spvalchev -------------------------------------------------------------------------------
267433075b6Spvalchev */
268433075b6Spvalchev #define floatx80_default_nan_high 0xFFFF
269433075b6Spvalchev #define floatx80_default_nan_low  LIT64( 0xC000000000000000 )
270433075b6Spvalchev 
271433075b6Spvalchev /*
272433075b6Spvalchev -------------------------------------------------------------------------------
273433075b6Spvalchev Returns 1 if the extended double-precision floating-point value `a' is a
274433075b6Spvalchev NaN; otherwise returns 0.
275433075b6Spvalchev -------------------------------------------------------------------------------
276433075b6Spvalchev */
floatx80_is_nan(floatx80 a)277433075b6Spvalchev static flag floatx80_is_nan( floatx80 a )
278433075b6Spvalchev {
279433075b6Spvalchev 
280433075b6Spvalchev     return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
281433075b6Spvalchev 
282433075b6Spvalchev }
283433075b6Spvalchev 
284433075b6Spvalchev /*
285433075b6Spvalchev -------------------------------------------------------------------------------
286433075b6Spvalchev Returns 1 if the extended double-precision floating-point value `a' is a
287433075b6Spvalchev signaling NaN; otherwise returns 0.
288433075b6Spvalchev -------------------------------------------------------------------------------
289433075b6Spvalchev */
floatx80_is_signaling_nan(floatx80 a)290433075b6Spvalchev flag floatx80_is_signaling_nan( floatx80 a )
291433075b6Spvalchev {
292433075b6Spvalchev     bits64 aLow;
293433075b6Spvalchev 
294433075b6Spvalchev     aLow = a.low & ~ LIT64( 0x4000000000000000 );
295433075b6Spvalchev     return
296433075b6Spvalchev            ( ( a.high & 0x7FFF ) == 0x7FFF )
297433075b6Spvalchev         && (bits64) ( aLow<<1 )
298433075b6Spvalchev         && ( a.low == aLow );
299433075b6Spvalchev 
300433075b6Spvalchev }
301433075b6Spvalchev 
302433075b6Spvalchev /*
303433075b6Spvalchev -------------------------------------------------------------------------------
304433075b6Spvalchev Returns the result of converting the extended double-precision floating-
305433075b6Spvalchev point NaN `a' to the canonical NaN format.  If `a' is a signaling NaN, the
306433075b6Spvalchev invalid exception is raised.
307433075b6Spvalchev -------------------------------------------------------------------------------
308433075b6Spvalchev */
floatx80ToCommonNaN(floatx80 a)309433075b6Spvalchev static commonNaNT floatx80ToCommonNaN( floatx80 a )
310433075b6Spvalchev {
311433075b6Spvalchev     commonNaNT z;
312433075b6Spvalchev 
313433075b6Spvalchev     if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
314433075b6Spvalchev     z.sign = a.high>>15;
315433075b6Spvalchev     z.low = 0;
316433075b6Spvalchev     z.high = a.low<<1;
317433075b6Spvalchev     return z;
318433075b6Spvalchev 
319433075b6Spvalchev }
320433075b6Spvalchev 
321433075b6Spvalchev /*
322433075b6Spvalchev -------------------------------------------------------------------------------
323433075b6Spvalchev Returns the result of converting the canonical NaN `a' to the extended
324433075b6Spvalchev double-precision floating-point format.
325433075b6Spvalchev -------------------------------------------------------------------------------
326433075b6Spvalchev */
commonNaNToFloatx80(commonNaNT a)327433075b6Spvalchev static floatx80 commonNaNToFloatx80( commonNaNT a )
328433075b6Spvalchev {
329433075b6Spvalchev     floatx80 z;
330433075b6Spvalchev 
331433075b6Spvalchev     z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
332433075b6Spvalchev     z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
333433075b6Spvalchev     return z;
334433075b6Spvalchev 
335433075b6Spvalchev }
336433075b6Spvalchev 
337433075b6Spvalchev /*
338433075b6Spvalchev -------------------------------------------------------------------------------
339433075b6Spvalchev Takes two extended double-precision floating-point values `a' and `b', one
340433075b6Spvalchev of which is a NaN, and returns the appropriate NaN result.  If either `a' or
341433075b6Spvalchev `b' is a signaling NaN, the invalid exception is raised.
342433075b6Spvalchev -------------------------------------------------------------------------------
343433075b6Spvalchev */
propagateFloatx80NaN(floatx80 a,floatx80 b)344433075b6Spvalchev static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
345433075b6Spvalchev {
346433075b6Spvalchev     flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
347433075b6Spvalchev 
348433075b6Spvalchev     aIsNaN = floatx80_is_nan( a );
349433075b6Spvalchev     aIsSignalingNaN = floatx80_is_signaling_nan( a );
350433075b6Spvalchev     bIsNaN = floatx80_is_nan( b );
351433075b6Spvalchev     bIsSignalingNaN = floatx80_is_signaling_nan( b );
352433075b6Spvalchev     a.low |= LIT64( 0xC000000000000000 );
353433075b6Spvalchev     b.low |= LIT64( 0xC000000000000000 );
354433075b6Spvalchev     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
355433075b6Spvalchev     if ( aIsSignalingNaN ) {
356433075b6Spvalchev         if ( bIsSignalingNaN ) goto returnLargerSignificand;
357433075b6Spvalchev         return bIsNaN ? b : a;
358433075b6Spvalchev     }
359433075b6Spvalchev     else if ( aIsNaN ) {
360433075b6Spvalchev         if ( bIsSignalingNaN | ! bIsNaN ) return a;
361433075b6Spvalchev  returnLargerSignificand:
362433075b6Spvalchev         if ( a.low < b.low ) return b;
363433075b6Spvalchev         if ( b.low < a.low ) return a;
364433075b6Spvalchev         return ( a.high < b.high ) ? a : b;
365433075b6Spvalchev     }
366433075b6Spvalchev     else {
367433075b6Spvalchev         return b;
368433075b6Spvalchev     }
369433075b6Spvalchev 
370433075b6Spvalchev }
371433075b6Spvalchev 
372433075b6Spvalchev #endif
373433075b6Spvalchev 
374433075b6Spvalchev #ifdef FLOAT128
375433075b6Spvalchev 
376433075b6Spvalchev /*
377433075b6Spvalchev -------------------------------------------------------------------------------
378433075b6Spvalchev The pattern for a default generated quadruple-precision NaN.  The `high' and
379433075b6Spvalchev `low' values hold the most- and least-significant bits, respectively.
380433075b6Spvalchev -------------------------------------------------------------------------------
381433075b6Spvalchev */
382433075b6Spvalchev #define float128_default_nan_high LIT64( 0xFFFF800000000000 )
383433075b6Spvalchev #define float128_default_nan_low  LIT64( 0x0000000000000000 )
384433075b6Spvalchev 
385433075b6Spvalchev /*
386433075b6Spvalchev -------------------------------------------------------------------------------
387433075b6Spvalchev Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
388433075b6Spvalchev otherwise returns 0.
389433075b6Spvalchev -------------------------------------------------------------------------------
390433075b6Spvalchev */
float128_is_nan(float128 a)391433075b6Spvalchev flag float128_is_nan( float128 a )
392433075b6Spvalchev {
393433075b6Spvalchev 
394433075b6Spvalchev     return
395433075b6Spvalchev            ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
396433075b6Spvalchev         && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
397433075b6Spvalchev 
398433075b6Spvalchev }
399433075b6Spvalchev 
400433075b6Spvalchev /*
401433075b6Spvalchev -------------------------------------------------------------------------------
402433075b6Spvalchev Returns 1 if the quadruple-precision floating-point value `a' is a
403433075b6Spvalchev signaling NaN; otherwise returns 0.
404433075b6Spvalchev -------------------------------------------------------------------------------
405433075b6Spvalchev */
float128_is_signaling_nan(float128 a)406433075b6Spvalchev flag float128_is_signaling_nan( float128 a )
407433075b6Spvalchev {
408433075b6Spvalchev 
409433075b6Spvalchev     return
410433075b6Spvalchev            ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
411433075b6Spvalchev         && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
412433075b6Spvalchev 
413433075b6Spvalchev }
414433075b6Spvalchev 
415433075b6Spvalchev /*
416433075b6Spvalchev -------------------------------------------------------------------------------
417433075b6Spvalchev Returns the result of converting the quadruple-precision floating-point NaN
418433075b6Spvalchev `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
419433075b6Spvalchev exception is raised.
420433075b6Spvalchev -------------------------------------------------------------------------------
421433075b6Spvalchev */
float128ToCommonNaN(float128 a)422433075b6Spvalchev static commonNaNT float128ToCommonNaN( float128 a )
423433075b6Spvalchev {
424433075b6Spvalchev     commonNaNT z;
425433075b6Spvalchev 
426433075b6Spvalchev     if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
427433075b6Spvalchev     z.sign = a.high>>63;
428433075b6Spvalchev     shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
429433075b6Spvalchev     return z;
430433075b6Spvalchev 
431433075b6Spvalchev }
432433075b6Spvalchev 
433433075b6Spvalchev /*
434433075b6Spvalchev -------------------------------------------------------------------------------
435433075b6Spvalchev Returns the result of converting the canonical NaN `a' to the quadruple-
436433075b6Spvalchev precision floating-point format.
437433075b6Spvalchev -------------------------------------------------------------------------------
438433075b6Spvalchev */
commonNaNToFloat128(commonNaNT a)439433075b6Spvalchev static float128 commonNaNToFloat128( commonNaNT a )
440433075b6Spvalchev {
441433075b6Spvalchev     float128 z;
442433075b6Spvalchev 
443433075b6Spvalchev     shift128Right( a.high, a.low, 16, &z.high, &z.low );
444433075b6Spvalchev     z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
445433075b6Spvalchev     return z;
446433075b6Spvalchev 
447433075b6Spvalchev }
448433075b6Spvalchev 
449433075b6Spvalchev /*
450433075b6Spvalchev -------------------------------------------------------------------------------
451433075b6Spvalchev Takes two quadruple-precision floating-point values `a' and `b', one of
452433075b6Spvalchev which is a NaN, and returns the appropriate NaN result.  If either `a' or
453433075b6Spvalchev `b' is a signaling NaN, the invalid exception is raised.
454433075b6Spvalchev -------------------------------------------------------------------------------
455433075b6Spvalchev */
propagateFloat128NaN(float128 a,float128 b)456433075b6Spvalchev static float128 propagateFloat128NaN( float128 a, float128 b )
457433075b6Spvalchev {
458433075b6Spvalchev     flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
459433075b6Spvalchev 
460433075b6Spvalchev     aIsNaN = float128_is_nan( a );
461433075b6Spvalchev     aIsSignalingNaN = float128_is_signaling_nan( a );
462433075b6Spvalchev     bIsNaN = float128_is_nan( b );
463433075b6Spvalchev     bIsSignalingNaN = float128_is_signaling_nan( b );
464433075b6Spvalchev     a.high |= LIT64( 0x0000800000000000 );
465433075b6Spvalchev     b.high |= LIT64( 0x0000800000000000 );
466433075b6Spvalchev     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
467433075b6Spvalchev     if ( aIsSignalingNaN ) {
468433075b6Spvalchev         if ( bIsSignalingNaN ) goto returnLargerSignificand;
469433075b6Spvalchev         return bIsNaN ? b : a;
470433075b6Spvalchev     }
471433075b6Spvalchev     else if ( aIsNaN ) {
472433075b6Spvalchev         if ( bIsSignalingNaN | ! bIsNaN ) return a;
473433075b6Spvalchev  returnLargerSignificand:
474433075b6Spvalchev         if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
475433075b6Spvalchev         if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
476433075b6Spvalchev         return ( a.high < b.high ) ? a : b;
477433075b6Spvalchev     }
478433075b6Spvalchev     else {
479433075b6Spvalchev         return b;
480433075b6Spvalchev     }
481433075b6Spvalchev 
482433075b6Spvalchev }
483433075b6Spvalchev 
484433075b6Spvalchev #endif
485