testfloat.c revision 1.2 1 /* $NetBSD: testfloat.c,v 1.2 2001/03/13 06:48:56 ross Exp $ */
2
3 /*
4 ===============================================================================
5
6 This C source file is part of TestFloat, Release 2a, a package of programs
7 for testing the correctness of floating-point arithmetic complying to the
8 IEC/IEEE Standard for Floating-Point.
9
10 Written by John R. Hauser. More information is available through the Web
11 page `http://HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/TestFloat.html'.
12
13 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
14 has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
15 TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
16 PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
17 AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
18
19 Derivative works are acceptable, even for commercial purposes, so long as
20 (1) they include prominent notice that the work is derivative, and (2) they
21 include prominent notice akin to these four paragraphs for those parts of
22 this code that are retained.
23
24 ===============================================================================
25 */
26
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <string.h>
30 #include "milieu.h"
31 #include "fail.h"
32 #include "softfloat.h"
33 #include "testCases.h"
34 #include "testLoops.h"
35 #include "systflags.h"
36 #include "testFunction.h"
37
38 static void catchSIGINT( int signalCode )
39 {
40
41 if ( stop ) exit( EXIT_FAILURE );
42 stop = TRUE;
43
44 }
45
46 int
47 main( int argc, char **argv )
48 {
49 char *argPtr;
50 flag functionArgument;
51 uint8 functionCode;
52 int8 operands, roundingPrecision, roundingMode;
53
54 fail_programName = "testfloat";
55 if ( argc <= 1 ) goto writeHelpMessage;
56 testCases_setLevel( 1 );
57 trueName = "soft";
58 testName = "syst";
59 errorStop = FALSE;
60 forever = FALSE;
61 maxErrorCount = 20;
62 trueFlagsPtr = &float_exception_flags;
63 testFlagsFunctionPtr = syst_float_flags_clear;
64 tininessModeName = 0;
65 functionArgument = FALSE;
66 functionCode = 0;
67 operands = 0;
68 roundingPrecision = 0;
69 roundingMode = 0;
70 --argc;
71 ++argv;
72 while ( argc && ( argPtr = argv[ 0 ] ) ) {
73 if ( argPtr[ 0 ] == '-' ) ++argPtr;
74 if ( strcmp( argPtr, "help" ) == 0 ) {
75 writeHelpMessage:
76 fputs(
77 "testfloat [<option>...] <function>\n"
78 " <option>: (* is default)\n"
79 " -help --Write this message and exit.\n"
80 " -list --List all testable functions and exit.\n"
81 " -level <num> --Testing level <num> (1 or 2).\n"
82 " * -level 1\n"
83 " -errors <num> --Stop each function test after <num> errors.\n"
84 " * -errors 20\n"
85 " -errorstop --Exit after first function with any error.\n"
86 " -forever --Test one function repeatedly (implies `-level 2').\n"
87 " -checkNaNs --Check for bitwise correctness of NaN results.\n"
88 #ifdef FLOATX80
89 " -precision32 --Only test rounding precision equivalent to float32.\n"
90 " -precision64 --Only test rounding precision equivalent to float64.\n"
91 " -precision80 --Only test maximum rounding precision.\n"
92 #endif
93 " -nearesteven --Only test rounding to nearest/even.\n"
94 " -tozero --Only test rounding to zero.\n"
95 " -down --Only test rounding down.\n"
96 " -up --Only test rounding up.\n"
97 " -tininessbefore --Underflow tininess detected before rounding.\n"
98 " -tininessafter --Underflow tininess detected after rounding.\n"
99 " <function>:\n"
100 " int32_to_<float> <float>_add <float>_eq\n"
101 " <float>_to_int32 <float>_sub <float>_le\n"
102 " <float>_to_int32_round_to_zero <float>_mul <float>_lt\n"
103 #ifdef BITS64
104 " int64_to_<float> <float>_div <float>_eq_signaling\n"
105 " <float>_to_int64 <float>_rem <float>_le_quiet\n"
106 " <float>_to_int64_round_to_zero <float>_lt_quiet\n"
107 " <float>_to_<float>\n"
108 " <float>_round_to_int\n"
109 " <float>_sqrt\n"
110 #else
111 " <float>_to_<float> <float>_div <float>_eq_signaling\n"
112 " <float>_round_to_int <float>_rem <float>_le_quiet\n"
113 " <float>_sqrt <float>_lt_quiet\n"
114 #endif
115 " -all1 --All 1-operand functions.\n"
116 " -all2 --All 2-operand functions.\n"
117 " -all --All functions.\n"
118 " <float>:\n"
119 " float32 --Single precision.\n"
120 " float64 --Double precision.\n"
121 #ifdef FLOATX80
122 " floatx80 --Extended double precision.\n"
123 #endif
124 #ifdef FLOAT128
125 " float128 --Quadruple precision.\n"
126 #endif
127 ,
128 stdout
129 );
130 return EXIT_SUCCESS;
131 }
132 else if ( strcmp( argPtr, "list" ) == 0 ) {
133 for ( functionCode = 1;
134 functionCode < NUM_FUNCTIONS;
135 ++functionCode
136 ) {
137 if ( functionExists[ functionCode ] ) {
138 puts( functions[ functionCode ].name );
139 }
140 }
141 return EXIT_SUCCESS;
142 }
143 else if ( strcmp( argPtr, "level" ) == 0 ) {
144 if ( argc < 2 ) goto optionError;
145 testCases_setLevel( atoi( argv[ 1 ] ) );
146 --argc;
147 ++argv;
148 }
149 else if ( strcmp( argPtr, "level1" ) == 0 ) {
150 testCases_setLevel( 1 );
151 }
152 else if ( strcmp( argPtr, "level2" ) == 0 ) {
153 testCases_setLevel( 2 );
154 }
155 else if ( strcmp( argPtr, "errors" ) == 0 ) {
156 if ( argc < 2 ) {
157 optionError:
158 fail( "`%s' option requires numeric argument", argv[ 0 ] );
159 }
160 maxErrorCount = atoi( argv[ 1 ] );
161 --argc;
162 ++argv;
163 }
164 else if ( strcmp( argPtr, "errorstop" ) == 0 ) {
165 errorStop = TRUE;
166 }
167 else if ( strcmp( argPtr, "forever" ) == 0 ) {
168 testCases_setLevel( 2 );
169 forever = TRUE;
170 }
171 else if ( ( strcmp( argPtr, "checkNaNs" ) == 0 )
172 || ( strcmp( argPtr, "checknans" ) == 0 ) ) {
173 checkNaNs = TRUE;
174 }
175 #ifdef FLOATX80
176 else if ( strcmp( argPtr, "precision32" ) == 0 ) {
177 roundingPrecision = 32;
178 }
179 else if ( strcmp( argPtr, "precision64" ) == 0 ) {
180 roundingPrecision = 64;
181 }
182 else if ( strcmp( argPtr, "precision80" ) == 0 ) {
183 roundingPrecision = 80;
184 }
185 #endif
186 else if ( ( strcmp( argPtr, "nearesteven" ) == 0 )
187 || ( strcmp( argPtr, "nearest_even" ) == 0 ) ) {
188 roundingMode = ROUND_NEAREST_EVEN;
189 }
190 else if ( ( strcmp( argPtr, "tozero" ) == 0 )
191 || ( strcmp( argPtr, "to_zero" ) == 0 ) ) {
192 roundingMode = ROUND_TO_ZERO;
193 }
194 else if ( strcmp( argPtr, "down" ) == 0 ) {
195 roundingMode = ROUND_DOWN;
196 }
197 else if ( strcmp( argPtr, "up" ) == 0 ) {
198 roundingMode = ROUND_UP;
199 }
200 else if ( strcmp( argPtr, "tininessbefore" ) == 0 ) {
201 float_detect_tininess = float_tininess_before_rounding;
202 }
203 else if ( strcmp( argPtr, "tininessafter" ) == 0 ) {
204 float_detect_tininess = float_tininess_after_rounding;
205 }
206 else if ( strcmp( argPtr, "all1" ) == 0 ) {
207 functionArgument = TRUE;
208 functionCode = 0;
209 operands = 1;
210 }
211 else if ( strcmp( argPtr, "all2" ) == 0 ) {
212 functionArgument = TRUE;
213 functionCode = 0;
214 operands = 2;
215 }
216 else if ( strcmp( argPtr, "all" ) == 0 ) {
217 functionArgument = TRUE;
218 functionCode = 0;
219 operands = 0;
220 }
221 else {
222 for ( functionCode = 1;
223 functionCode < NUM_FUNCTIONS;
224 ++functionCode
225 ) {
226 if ( strcmp( argPtr, functions[ functionCode ].name ) == 0 ) {
227 break;
228 }
229 }
230 if ( functionCode == NUM_FUNCTIONS ) {
231 fail( "Invalid option or function `%s'", argv[ 0 ] );
232 }
233 if ( ! functionExists[ functionCode ] ) {
234 fail(
235 "Function `%s' is not supported or cannot be tested",
236 argPtr
237 );
238 }
239 functionArgument = TRUE;
240 }
241 --argc;
242 ++argv;
243 }
244 if ( ! functionArgument ) fail( "Function argument required" );
245 (void) signal( SIGINT, catchSIGINT );
246 (void) signal( SIGTERM, catchSIGINT );
247 if ( functionCode ) {
248 if ( forever ) {
249 if ( ! roundingPrecision ) roundingPrecision = 80;
250 if ( ! roundingMode ) roundingMode = ROUND_NEAREST_EVEN;
251 }
252 testFunction( functionCode, roundingPrecision, roundingMode );
253 }
254 else {
255 if ( forever ) {
256 fail( "Can only test one function with `-forever' option" );
257 }
258 if ( operands == 1 ) {
259 for ( functionCode = 1;
260 functionCode < NUM_FUNCTIONS;
261 ++functionCode
262 ) {
263 if ( functionExists[ functionCode ]
264 && ( functions[ functionCode ].numInputs == 1 ) ) {
265 testFunction(
266 functionCode, roundingPrecision, roundingMode );
267 }
268 }
269 }
270 else if ( operands == 2 ) {
271 for ( functionCode = 1;
272 functionCode < NUM_FUNCTIONS;
273 ++functionCode
274 ) {
275 if ( functionExists[ functionCode ]
276 && ( functions[ functionCode ].numInputs == 2 ) ) {
277 testFunction(
278 functionCode, roundingPrecision, roundingMode );
279 }
280 }
281 }
282 else {
283 for ( functionCode = 1;
284 functionCode < NUM_FUNCTIONS;
285 ++functionCode
286 ) {
287 if ( functionExists[ functionCode ] ) {
288 testFunction(
289 functionCode, roundingPrecision, roundingMode );
290 }
291 }
292 }
293 }
294 exitWithStatus();
295 return 0;
296 }
297
298