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