1 /*	$NetBSD: testfloat.c,v 1.5 2002/02/21 07:38:16 itojun Exp $	*/
2 
3 /* This is a derivative work. */
4 
5 /*-
6  * Copyright (c) 2001 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Ross Harvey.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *        This product includes software developed by the NetBSD
23  *        Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40 
41 /*
42 ===============================================================================
43 
44 This C source file is part of TestFloat, Release 2a, a package of programs
45 for testing the correctness of floating-point arithmetic complying to the
46 IEC/IEEE Standard for Floating-Point.
47 
48 Written by John R. Hauser.  More information is available through the Web
49 page `http://HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/TestFloat.html'.
50 
51 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
52 has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
53 TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
54 PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
55 AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
56 
57 Derivative works are acceptable, even for commercial purposes, so long as
58 (1) they include prominent notice that the work is derivative, and (2) they
59 include prominent notice akin to these four paragraphs for those parts of
60 this code that are retained.
61 
62 ===============================================================================
63 */
64 
65 #include <sys/cdefs.h>
66 #ifndef __lint
67 __COPYRIGHT("@(#) Copyright (c) 2001\n\
68 	The NetBSD Foundation, inc. All rights reserved.\n");
69 __RCSID("$NetBSD: testfloat.c,v 1.5 2002/02/21 07:38:16 itojun Exp $");
70 #endif /* !__lint */
71 
72 #include <stdlib.h>
73 #include <signal.h>
74 #include <string.h>
75 #include "milieu.h"
76 #include "fail.h"
77 #include "softfloat.h"
78 #include "testCases.h"
79 #include "testLoops.h"
80 #include "systflags.h"
81 #include "testFunction.h"
82 
83 static void catchSIGINT( int signalCode )
84 {
85 
86     if ( stop ) exit( EXIT_FAILURE );
87     stop = TRUE;
88 
89 }
90 
91 int
92 main( int argc, char **argv )
93 {
94     char *argPtr;
95     flag functionArgument;
96     uint8 functionCode;
97     int8 operands, roundingPrecision, roundingMode;
98 
99     fail_programName = "testfloat";
100     if ( argc <= 1 ) goto writeHelpMessage;
101     testCases_setLevel( 1 );
102     trueName = "soft";
103     testName = "syst";
104     errorStop = FALSE;
105     forever = FALSE;
106     maxErrorCount = 20;
107     trueFlagsPtr = &float_exception_flags;
108     testFlagsFunctionPtr = syst_float_flags_clear;
109     tininessModeName = 0;
110     functionArgument = FALSE;
111     functionCode = 0;
112     operands = 0;
113     roundingPrecision = 0;
114     roundingMode = 0;
115     --argc;
116     ++argv;
117     while ( argc && ( argPtr = argv[ 0 ] ) ) {
118         if ( argPtr[ 0 ] == '-' ) ++argPtr;
119         if ( strcmp( argPtr, "help" ) == 0 ) {
120  writeHelpMessage:
121             fputs(
122 "testfloat [<option>...] <function>\n"
123 "  <option>:  (* is default)\n"
124 "    -help            --Write this message and exit.\n"
125 "    -list            --List all testable functions and exit.\n"
126 "    -level <num>     --Testing level <num> (1 or 2).\n"
127 " *  -level 1\n"
128 "    -errors <num>    --Stop each function test after <num> errors.\n"
129 " *  -errors 20\n"
130 "    -errorstop       --Exit after first function with any error.\n"
131 "    -forever         --Test one function repeatedly (implies `-level 2').\n"
132 "    -checkNaNs       --Check for bitwise correctness of NaN results.\n"
133 #ifdef FLOATX80
134 "    -precision32     --Only test rounding precision equivalent to float32.\n"
135 "    -precision64     --Only test rounding precision equivalent to float64.\n"
136 "    -precision80     --Only test maximum rounding precision.\n"
137 #endif
138 "    -nearesteven     --Only test rounding to nearest/even.\n"
139 "    -tozero          --Only test rounding to zero.\n"
140 "    -down            --Only test rounding down.\n"
141 "    -up              --Only test rounding up.\n"
142 "    -tininessbefore  --Underflow tininess detected before rounding.\n"
143 "    -tininessafter   --Underflow tininess detected after rounding.\n"
144 "  <function>:\n"
145 "    int32_to_<float>                 <float>_add   <float>_eq\n"
146 "    <float>_to_int32                 <float>_sub   <float>_le\n"
147 "    <float>_to_int32_round_to_zero   <float>_mul   <float>_lt\n"
148 #ifdef BITS64
149 "    int64_to_<float>                 <float>_div   <float>_eq_signaling\n"
150 "    <float>_to_int64                 <float>_rem   <float>_le_quiet\n"
151 "    <float>_to_int64_round_to_zero                 <float>_lt_quiet\n"
152 "    <float>_to_<float>\n"
153 "    <float>_round_to_int\n"
154 "    <float>_sqrt\n"
155 #else
156 "    <float>_to_<float>               <float>_div   <float>_eq_signaling\n"
157 "    <float>_round_to_int             <float>_rem   <float>_le_quiet\n"
158 "    <float>_sqrt                                   <float>_lt_quiet\n"
159 #endif
160 "    -all1            --All 1-operand functions.\n"
161 "    -all2            --All 2-operand functions.\n"
162 "    -all             --All functions.\n"
163 "  <float>:\n"
164 "    float32          --Single precision.\n"
165 "    float64          --Double precision.\n"
166 #ifdef FLOATX80
167 "    floatx80         --Extended double precision.\n"
168 #endif
169 #ifdef FLOAT128
170 "    float128         --Quadruple precision.\n"
171 #endif
172                 ,
173                 stdout
174             );
175             return EXIT_SUCCESS;
176         }
177         else if ( strcmp( argPtr, "list" ) == 0 ) {
178             for ( functionCode = 1;
179                   functionCode < NUM_FUNCTIONS;
180                   ++functionCode
181                 ) {
182                 if ( functionExists[ functionCode ] ) {
183                     puts( functions[ functionCode ].name );
184                 }
185             }
186             return EXIT_SUCCESS;
187         }
188         else if ( strcmp( argPtr, "level" ) == 0 ) {
189             if ( argc < 2 ) goto optionError;
190             testCases_setLevel( atoi( argv[ 1 ] ) );
191             --argc;
192             ++argv;
193         }
194         else if ( strcmp( argPtr, "level1" ) == 0 ) {
195             testCases_setLevel( 1 );
196         }
197         else if ( strcmp( argPtr, "level2" ) == 0 ) {
198             testCases_setLevel( 2 );
199         }
200         else if ( strcmp( argPtr, "errors" ) == 0 ) {
201             if ( argc < 2 ) {
202      optionError:
203                 fail( "`%s' option requires numeric argument", argv[ 0 ] );
204             }
205             maxErrorCount = atoi( argv[ 1 ] );
206             --argc;
207             ++argv;
208         }
209         else if ( strcmp( argPtr, "errorstop" ) == 0 ) {
210             errorStop = TRUE;
211         }
212         else if ( strcmp( argPtr, "forever" ) == 0 ) {
213             testCases_setLevel( 2 );
214             forever = TRUE;
215         }
216         else if (    ( strcmp( argPtr, "checkNaNs" ) == 0 )
217                   || ( strcmp( argPtr, "checknans" ) == 0 ) ) {
218             checkNaNs = TRUE;
219         }
220 #ifdef FLOATX80
221         else if ( strcmp( argPtr, "precision32" ) == 0 ) {
222             roundingPrecision = 32;
223         }
224         else if ( strcmp( argPtr, "precision64" ) == 0 ) {
225             roundingPrecision = 64;
226         }
227         else if ( strcmp( argPtr, "precision80" ) == 0 ) {
228             roundingPrecision = 80;
229         }
230 #endif
231         else if (    ( strcmp( argPtr, "nearesteven" ) == 0 )
232                   || ( strcmp( argPtr, "nearest_even" ) == 0 ) ) {
233             roundingMode = ROUND_NEAREST_EVEN;
234         }
235         else if (    ( strcmp( argPtr, "tozero" ) == 0 )
236                   || ( strcmp( argPtr, "to_zero" ) == 0 ) ) {
237             roundingMode = ROUND_TO_ZERO;
238         }
239         else if ( strcmp( argPtr, "down" ) == 0 ) {
240             roundingMode = ROUND_DOWN;
241         }
242         else if ( strcmp( argPtr, "up" ) == 0 ) {
243             roundingMode = ROUND_UP;
244         }
245         else if ( strcmp( argPtr, "tininessbefore" ) == 0 ) {
246             float_detect_tininess = float_tininess_before_rounding;
247         }
248         else if ( strcmp( argPtr, "tininessafter" ) == 0 ) {
249             float_detect_tininess = float_tininess_after_rounding;
250         }
251         else if ( strcmp( argPtr, "all1" ) == 0 ) {
252             functionArgument = TRUE;
253             functionCode = 0;
254             operands = 1;
255         }
256         else if ( strcmp( argPtr, "all2" ) == 0 ) {
257             functionArgument = TRUE;
258             functionCode = 0;
259             operands = 2;
260         }
261         else if ( strcmp( argPtr, "all" ) == 0 ) {
262             functionArgument = TRUE;
263             functionCode = 0;
264             operands = 0;
265         }
266         else {
267             for ( functionCode = 1;
268                   functionCode < NUM_FUNCTIONS;
269                   ++functionCode
270                 ) {
271                 if ( strcmp( argPtr, functions[ functionCode ].name ) == 0 ) {
272                     break;
273                 }
274             }
275             if ( functionCode == NUM_FUNCTIONS ) {
276                 fail( "Invalid option or function `%s'", argv[ 0 ] );
277             }
278             if ( ! functionExists[ functionCode ] ) {
279                 fail(
280                     "Function `%s' is not supported or cannot be tested",
281                     argPtr
282                 );
283             }
284             functionArgument = TRUE;
285         }
286         --argc;
287         ++argv;
288     }
289     if ( ! functionArgument ) fail( "Function argument required" );
290     (void) signal( SIGINT, catchSIGINT );
291     (void) signal( SIGTERM, catchSIGINT );
292     if ( functionCode ) {
293         if ( forever ) {
294             if ( ! roundingPrecision ) roundingPrecision = 80;
295             if ( ! roundingMode ) roundingMode = ROUND_NEAREST_EVEN;
296         }
297         testFunction( functionCode, roundingPrecision, roundingMode );
298     }
299     else {
300         if ( forever ) {
301             fail( "Can only test one function with `-forever' option" );
302         }
303         if ( operands == 1 ) {
304             for ( functionCode = 1;
305                   functionCode < NUM_FUNCTIONS;
306                   ++functionCode
307                 ) {
308                 if (    functionExists[ functionCode ]
309                      && ( functions[ functionCode ].numInputs == 1 ) ) {
310                     testFunction(
311                         functionCode, roundingPrecision, roundingMode );
312                 }
313             }
314         }
315         else if ( operands == 2 ) {
316             for ( functionCode = 1;
317                   functionCode < NUM_FUNCTIONS;
318                   ++functionCode
319                 ) {
320                 if (    functionExists[ functionCode ]
321                      && ( functions[ functionCode ].numInputs == 2 ) ) {
322                     testFunction(
323                         functionCode, roundingPrecision, roundingMode );
324                 }
325             }
326         }
327         else {
328             for ( functionCode = 1;
329                   functionCode < NUM_FUNCTIONS;
330                   ++functionCode
331                 ) {
332                 if ( functionExists[ functionCode ] ) {
333                     testFunction(
334                         functionCode, roundingPrecision, roundingMode );
335                 }
336             }
337         }
338     }
339     exitWithStatus();
340     return 0;
341 }
342 
343