No subject
Fred Tydeman
sun!uunet.UU.NET!ibmsupt!ibmpa!tydeman
Thu Aug 2 13:59:48 PDT 1990
Subject: Code to test support of infinity and Not-a-Number as strings
The following is a program to test an implementation's support for
infinity and Not-a-Number (NaN) as strings for input and output
conversions. It is based upon IBM's proposal to the NCEG (Numerical C
Extensions Group). We believe that a short standard string
representation for infinity is needed, namely, INF. We believe that a
short standard string representation for quiet NaN is needed, namely
NaNQ. We believe that a short standard string representation for a
signaling NaN is needed, namely, NaNS. Our reading of IEEE-854 says the
string NaN should be recognized as a signaling NaN. The representation
in the case of the general NaN, one where the significand is an (almost)
arbitrary value, is to be determined. Some implementations have used
NaN() as a starting point for an arbitrary NaN, where the () were to be
filled in by some string of a format to be determined.
Output Input Representing
------ ----- ------------
INF INF or infinity Infinity
NaNQ NaNQ Quiet Not-a-Number
NaNS NaNS or NaN Signaling Not-a-Number
NaN() NaN() General Not-a-Number (to be done)
The code follows:
/* Unclassified */
/* */
/* Copyright IBM Corporation 1989, 1990 */
/* */
/* All Rights Reserved */
/* */
/* Permission to use, copy, modify, and distribute this software and */
/* its documentation without fee is hereby granted, provided that */
/* the above copyright notice appear in all copies and that both */
/* that copyright notice and this permission notice appear in */
/* supporting documentation, and that the name of IBM not be used in */
/* advertising or publicity pertaining to distribution of the */
/* software without specific, written prior permission. The user */
/* understands and agrees that this program and any derivative works */
/* are to be used solely for experimental uses and are not to be */
/* sold, licensed or distributed for a fee or profit, or be */
/* commercially exploited in any manner. */
/* */
/* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, */
/* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
/* FOR A PARTICULAR USE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY */
/* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER */
/* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
/* THIS SOFTWARE. */
/* */
/*=====================================================================*/
/* */
/* Purpose of this test: */
/* */
/* To test your implementation's support for infinity and NaN (Not a */
/* Number) from IEEE-854 Floating-Point Standard in ANSI "C" as */
/* extended by a proposal to the Numerical "C" Extensions Group in */
/* the area of scanf, printf, strtod, atof, and gcvt. In */
/* particular, the string "INF" for infinity, "NaNQ" for quiet NaN, */
/* and "NaNS" for signaling NaN. */
/* */
/* Assumptions: */
/* */
/* Your system (hardware and software) support IEEE-754 or IEEE-854 */
/* in binary (not decimal) mode. Your system supports the sign bit */
/* on NaNs. Your system is (close to) ANSI "C" compliant. C's */
/* float is mapped to a 32-bit IEEE single which is a 4 byte item. */
/* C's double is mapped to a 64-bit IEEE double which is an 8 byte */
/* item. The default locale ("C") recognizes the NCEG strings (just */
/* doing IEEE math with inexact and/or NaN exceptions, causes */
/* undefined behavior (ANSI "C", section 3.3, fifth paragraph), so */
/* once you have undefined behavior in your program, having the */
/* default locale recognize the NCEG strings may be allowed). */
/* */
/* What you need to do to run this: */
/* */
/* 1) Modify the #defines for your system. They are related to how */
/* much output you want (ECHO_GOOD), the internal values for */
/* Signaling and Quiet NaN (..NAN.), your compiler's support for */
/* 'const' (CONST), 'volatile' (VOLATILE), '(void *)' (VOID_STAR) */
/* and if you wish to test gcvt (CVT), which is not part of ANSI */
/* "C". These defines are all located just after these */
/* instructions and before the meaning of the error codes. The */
/* rest of the defines and code should not need to be modified. */
/* */
/* 2) Compile the code: cc naninfpd.c */
/* */
/* 3) Run the code: a.out */
/* */
/* 4) Check the output. If everything is working correctly, then */
/* each test case will output a line that starts with OK. If */
/* something is wrong, it will attempt to tell you what is */
/* wrong. All error messages have a two digit number so you can */
/* find the exact line in error, in the code, easier. */
/* */
/*=====================================================================*/
/* This should be set up to compile and run on your various */
/* platforms by changing the next several #defines. */
/* */
/*---------------------------------------------------------------------*/
/* To control 'OK:' messages, choose one of the following two lines: */
#undef ECHO_GOOD /* Silence if all is OK. */
#define ECHO_GOOD 1 /* Let user know tests passed. */
/*---------------------------------------------------------------------*/
/* Define machine dependent constants: IEEE binary format: */
/* s = single precision, d = double precision */
/* p = positive, m = minus */
#define dpNANS "0x7ff7ffffffffffff"
#define dmNANS "0xfff7ffffffffffff"
#define spNANS "0x7fbfffff"
#define smNANS "0xffbfffff"
#define dpNANQ "0x7fffffffffffffff"
#define dmNANQ "0xffffffffffffffff"
#define spNANQ "0x7fffffff"
#define smNANQ "0xffffffff"
#if 0 /* another example of IEEE-754 values */
#define dpNANS "0x7ff5555555555555"
#define dmNANS "0xfff5555555555555"
#define spNANS "0x7f855555"
#define smNANS "0xff855555"
#define dpNANQ "0x7ff8000000000000"
#define dmNANQ "0xfff8000000000000"
#define spNANQ "0x7fc00000"
#define smNANQ "0xffc00000"
#endif
/*---------------------------------------------------------------------*/
/* Define compiler dependent constants: */
#define CONST const /* or blanks if not full ANSI "C" */
#define VOLATILE volatile /* or blanks if not full ANSI "C" */
#define VOID_STAR (void *) /* or blanks if not full ANSI "C" */
/*---------------------------------------------------------------------*/
/* To control testing 'gcvt', choose one of the following two lines: */
#undef CVT /* gcvt not supported. */
#define CVT 1 /* If want to test gcvt routines. */
/*---------------------------------------------------------------------*/
/* The rest of the code should not need to be changed; just above defs */
/*=====================================================================*/
/* */
/* Meaning of the error codes: */
/* */
/* 00 The internal representation of a NaNQ as returned by sscanf is */
/* different than the result of 0.0 / 0.0 (ignoring the sign bit). */
/* This assumes that there is one preferred internal representation */
/* of quiet NaNs, that is 0.0 / 0.0 is the same as inf / inf is the */
/* same as inf - inf, and that sscanf should return that number. */
/* */
/* 01 sprintf of a float value (promoted to double) via "%.0e" */
/* produced a string different than what was expected. What was */
/* produced and what was expected are listed. The most common */
/* error is the value is converted to a different string */
/* representation than the suggested one for NaN and/or infinity. */
/* 02 sscanf of a string via "%e" into a float produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 03 sscanf of a string via "%e" into a float failed to process that */
/* string. The string is listed. The most common cause is your */
/* system does not support the suggested string representations for */
/* NaN and/or infinity. */
/* */
/* 04 sprintf of a float value (promoted to double) via "%.0E" */
/* produced a string different than what was expected. What was */
/* produced and what was expected are listed. The most common */
/* error is the value is converted to a different string */
/* representation than the suggested one for NaN and/or infinity. */
/* 05 sscanf of a string via "%E" into a float produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. The */
/* most common error is the value is converted and stored as a */
/* double, rather, than as a float. */
/* 06 sscanf of a string via "%E" into a float failed to process that */
/* string. The most common cause is your system does not support */
/* the suggested string representations for NaN and/or infinity. */
/* */
/* 07 sprintf of a float value (promoted to double) via "%.0f" */
/* produced a string different than what was expected. What was */
/* produced and what was expected are listed. The most common */
/* error is the value is converted to a different string */
/* representation than the suggested one for NaN and/or infinity. */
/* 08 sscanf of a string via "%f" into a float produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 09 sscanf of a string via "%f" into a float failed to process that */
/* string. The most common cause is your system does not support */
/* the suggested string representations for NaN and/or infinity. */
/* */
/* 10 sprintf of a float value (promoted to double) via "%.0g" */
/* produced a string different than what was expected. What was */
/* produced and what was expected are listed. The most common */
/* error is the value is converted to a different string */
/* representation than the suggested one for NaN and/or infinity. */
/* 11 sscanf of a string via "%g" into a float produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 12 sscanf of a string via "%g" into a float failed to process that */
/* string. The most common cause is your system does not support */
/* the suggested string representations for NaN and/or infinity. */
/* */
/* 13 sprintf of a float value (promoted to double) via "%.0G" */
/* produced a string different than what was expected. What was */
/* produced and what was expected are listed. The most common */
/* error is the value is converted to a different string */
/* representation than the suggested one for NaN and/or infinity. */
/* 14 sscanf of a string via "%G" into a float produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. The */
/* most common error is the value is converted and stored as a */
/* double, rather, than as a float. */
/* 15 sscanf of a string via "%G" into a float failed to process that */
/* string. The most common cause is your system does not support */
/* the suggested string representations for NaN and/or infinity. */
/* */
/* 16 sprintf of a double value via "%.0e" produced a string different */
/* than what was expected. What was produced and what was expected */
/* are listed. The most common error is the value is converted to */
/* a different string representation than the suggested one for NaN */
/* and/or infinity. */
/* 17 sscanf of a string via "%le" into a double produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 18 sscanf of a string via "%le" into a double failed to process */
/* that string. The most common cause is your system does not */
/* support the suggested string representations for NaN and/or */
/* infinity. */
/* */
/* 19 sprintf of a double value via "%.0E" produced a string different */
/* than what was expected. What was produced and what was expected */
/* are listed. The most common error is the value is converted to */
/* a different string representation than the suggested one for NaN */
/* and/or infinity. */
/* 20 sscanf of a string via "%lE" into a double produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 21 sscanf of a string via "%lE" into a double failed to process */
/* that string. The most common cause is your system does not */
/* support the suggested string representations for NaN and/or */
/* infinity. */
/* */
/* 22 sprintf of a double value via "%.0f" produced a string different */
/* than what was expected. What was produced and what was expected */
/* are listed. The most common error is the value is converted to */
/* a different string representation than the suggested one for NaN */
/* and/or infinity. */
/* 23 sscanf of a string via "%lf" into a double produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 24 sscanf of a string via "%lf" into a double failed to process */
/* that string. The most common cause is your system does not */
/* support the suggested string representations for NaN and/or */
/* infinity. */
/* */
/* 25 sprintf of a double value via "%.0g" produced a string different */
/* than what was expected. What was produced and what was expected */
/* are listed. The most common error is the value is converted to */
/* a different string representation than the suggested one for NaN */
/* and/or infinity. */
/* 26 sscanf of a string via "%lg" into a double produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 27 sscanf of a string via "%lg" into a double failed to process */
/* that string. The most common cause is your system does not */
/* support the suggested string representations for NaN and/or */
/* infinity. */
/* */
/* 28 sprintf of a double value via "%.0G" produced a string different */
/* than what was expected. What was produced and what was expected */
/* are listed. The most common error is the value is converted to */
/* a different string representation than the suggested one for NaN */
/* and/or infinity. */
/* 29 sscanf of a string via "%lG" into a double produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 30 sscanf of a string via "%lG" into a double failed to process */
/* that string. The most common cause is your system does not */
/* support the suggested string representations for NaN and/or */
/* infinity. */
/* */
/* 31 atof of a string into a double produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 32 atof of a string into a double failed to process that string. */
/* The most common cause is your system does not support the */
/* suggested string representations for NaN and/or infinity. */
/* */
/* 33 strtod of a string returned the pointer to the final string with */
/* the wrong value. The character that pointer is pointing to, the */
/* character that was expected, and the string are listed. The */
/* characters are printed in hex, since a nul (00) is the expected */
/* character in many cases. The most common cause is your system */
/* does not support the suggested string representations for NaN */
/* and/or infinity. */
/* 34 strtod of a string into a double produced an internal */
/* representation different that what was expected. The input */
/* string, what was produced and what was expected are listed. */
/* 35 strtod of a string into a double failed to process that string. */
/* The most common cause is your system does not support the */
/* suggested string representations for NaN and/or infinity. */
/* */
/* 36 gcvt of a double value produced a string different than what was */
/* expected. What was produced, what was expected, and the string */
/* string "converted" by strtod to a double to then be converted by */
/* gcvt are listed. The most common error is the value is */
/* converted to a different string representation than the */
/* suggested one for NaN and/or infinity. The other common error */
/* is the preceding strtod produced the wrong value internally, so */
/* gcvt is given the wrong value to convert (make sure strtod is */
/* correct first). */
/* */
/* 45 This program was unable to determine how floating-point numbers */
/* are stored internally. It tries to do the two common ways of */
/* big-endian (most significant byte at low address) and */
/* little-endian (least significant byte at low address). Because */
/* of this, the results of the other tests are suspect. This is */
/* caused by not meeting the assumptions this program makes. */
/* */
/* 50 The internal representation of -NaNQ is the same as +NaNQ as a */
/* float. This can happen because the floating point unit does not */
/* support signed NaNs (which is allowed by the IEEE-754/854 */
/* standards). If this is the case, then many of the other tests */
/* will fail. */
/* 51 The internal representation of -NaNQ is the same as +NaNQ as a */
/* double. This can happen because the floating point unit does */
/* not support signed NaNs (which is allowed by the IEEE-754/854 */
/* standards). If this is the case, then many of the other tests */
/* will fail. */
/* */
/*=====================================================================*/
/* This program has been run on several systems (hardware/software */
/* combinations) from various vendors. The following problems have */
/* been found: */
/* Segmentation fault on first sscanf */
/* sscanf("INF","%E",&float) done as double */
/* sscanf("INF","%G",&float) done as double */
/* sprintf(out,"%.0f",-INF) outputs INF (drops sign) */
/* gcvt(Inf) outputs I.NF; should be INF */
/* gcvt(Inf) outputs 0.INF; should be INF */
/* atof("INF") is 0; should be infinity */
/* strtod("INF") is 0; should be infinity */
/* strtod("INFINITE",&ptr) returns bad pointer location */
/* atof("-INF") is 1.e-314; should be -infinity */
/* strtod("-INF") is 1.e-314; should be -infinity */
/* sscanf("1e4294967296") is 1, not infinity */
/* strtod("1e4294967296") is 1, not infinity */
/* atof("1e4294967296") is 1, not infinity */
/* Signaling NaNs not handled, in or out */
/* Signed NaNs not handled, ie -NaN == NaN */
/* 0./0. internally is not same as sscanf(NaNQ) */
/* sprintf(out,"%.0f",-NaNS) outputs NaNS (drops sign) */
/* sprintf(out,"%.0e",-NAN())outputs NAN() (drops sign) */
/* sprintf(out,"%.0f",-NAN())outputs NAN() (drops sign) */
/* sprintf(out,"%.0g",-NAN())outputs NAN() (drops sign) */
/* sprintf(out,"%.0e",NaNS) outputs NaNS (float to double convert) */
/* sprintf(out,"%.0f",NaNS) outputs NaNS (float to double convert) */
/* sprintf(out,"%.0g",NaNS) outputs NaNS (float to double convert) */
/* strtod("NaN",&ptr) returns bad pointer location */
/* sprintf(out,"%.0g",1) outputs 0.e+00 */
/* sprintf(out,"%.0G",1) outputs 0.E+00 */
/* sscanf("1/0","%E",&float) done as double */
/* sscanf("1/0","%G",&float) done as double */
/* gcvt(1) outputs 1.000000000000, not 1 */
/* gcvt(-1) outputs -1.000000000000, not -1 */
/* gcvt(0) outputs 0.000000000000, not 0 */
/* gcvt(-0) outputs -0.000000000000, not -0 */
/* sprintf(out,"%.0f",-0) output 0; should be -0 */
/* sprintf(out,"%.0g",-0) output 0; should be -0 */
/* sprintf(out,"%.0G",-0) output 0; should be -0 */
/* atof("-0") is 1.e-314; should be -0 */
/* compiler not support \ as last character of line */
/*=====================================================================*/
#define dpZERO "0x0000000000000000"
#define dmZERO "0x8000000000000000"
#define spZERO "0x00000000"
#define smZERO "0x80000000"
#define dpONE "0x3ff0000000000000"
#define dmONE "0xbff0000000000000"
#define spONE "0x3f800000"
#define smONE "0xbf800000"
#define dpINF "0x7ff0000000000000"
#define dmINF "0xfff0000000000000"
#define spINF "0x7f800000"
#define smINF "0xff800000"
#define PI 3.1415926535 /* "random" number */
#define Nul '\0'
/* This set of defines determine how data is stored (big/little endian)*/
#define LITTLE_ENDIAN 1234 /* least-significant byte first
* (80x86, vax) */
#define BIG_ENDIAN 4321 /* most-significant byte first
* (680x0, IBM S/370, net) */
/*---------------------------------------------------------------------*/
/* These next strings are the reason for this test. They are the */
/* suggested strings for infinity, Signaling NaN, and Quiet NaN */
/* to be processed by scanf, printf, strtod, ... functions. */
/*---------------------------------------------------------------------*/
#define dpInf "INF"
#define dmInf "-INF"
#define spInf "INF"
#define smInf "-INF"
#define dpNS "NaNS"
#define dmNS "-NaNS"
#define spNS "NaNQ" /* float NaNS promoted to double NaNQ by printf*/
#define smNS "-NaNQ" /* " */
#define dpNQ "NaNQ"
#define dmNQ "-NaNQ"
#define spNQ "NaNQ" /* float NaNQ promoted to double NaNQ by printf*/
#define smNQ "-NaNQ" /* " */
/*=====================================================================*/
#include <stdio.h>
#include <stdlib.h> /* atof, strtod */
#include <string.h>
/*=====================================================================*/
int bad;
int ok;
char s[19]; /* 0x1234567812345678\0 */
char ss[19];
int byte_order; /* big or little endian determined at run time */
/*=====================================================================*/
char * hexer_8(s,p) /* convert a 8 byte double into 16 hex chars */
char * s;
CONST double * p;
{
char * h;
unsigned char * q;
int i;
char c[3];
h = s;
q = (unsigned char *)(VOID_STAR p);
*h = '0'; h++;
*h = 'x'; h++;
if ( byte_order == LITTLE_ENDIAN ){
for(i=7;i>=0;i--){ /* right to left for 80386 */
sprintf(c,"%02x",(unsigned int)((unsigned char)(q[i])));
*h = c[0]; h++;
*h = c[1]; h++;
};
}else{ /* byte_order == BIG_ENDIAN */
for(i=0;i<=7;i++){ /* left to right for 68030 */
sprintf(c,"%02x",(unsigned int)((unsigned char)(q[i])));
*h = c[0]; h++;
*h = c[1]; h++;
};
};
*h = '\0';
return(s);
}/* end hexer_8 */
/*=====================================================================*/
char * hexer_4(s,p) /* convert 4 byte float into 8 hex chars */
char * s;
CONST float * p;
{
char * h;
unsigned char * q;
int i;
char c[3];
h = s;
q = (unsigned char *)(VOID_STAR p);
*h = '0'; h++;
*h = 'x'; h++;
if ( byte_order == LITTLE_ENDIAN ){
for(i=3;i>=0;i--){ /* right to left for 80386 */
sprintf(c,"%02x",(unsigned int)((unsigned char)(q[i])));
*h = c[0]; h++;
*h = c[1]; h++;
};
}else{ /* byte_order == BIG_ENDIAN */
for(i=0;i<=3;i++){ /* left to right for 68030 */
sprintf(c,"%02x",(unsigned int)((unsigned char)(q[i])));
*h = c[0]; h++;
*h = c[1]; h++;
};
};
*h = '\0';
return(s);
}/* end hexer_4 */
/*=====================================================================*/
test( in, hexd, hexf, doutfgG, doute, doutE, outfgG, oute, outE, strch )
CONST char * in; /* character string to process */
CONST char * hexd; /* double precision, double, internal format */
CONST char * hexf; /* single precision, float, internal format */
CONST char * doutfgG; /* double f, g, G format */
CONST char * doute; /* double e format */
CONST char * doutE; /* double E format */
CONST char * outfgG; /* float f, g, G format */
CONST char * oute; /* float e format */
CONST char * outE; /* float E format */
CONST char strch; /* char strtod should point to */
{
int i;
VOLATILE float f;
VOLATILE double dd;
char strout[32];
char strhex[32];
char * c_ptr;
/*----------------------------- Test floats ---------------------------*/
f = PI;
i = sscanf(in,"%e",&f);
if(i==1){
hexer_4(strhex,&f);
if(strcmp(hexf,strhex)==0){
; sprintf(strout,"%.0e",f);
; if(strcmp(oute,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,oute,hexf);
#endif
; }else{
; bad++;
; printf("01:sprintf( %%e) produced(%s), expected(%s) for(%s)\n",
strout,oute,in);
; }; /* fi */
}else{
; bad++;
; printf("02:sscanf( %%e) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexf,in);
}; /* fi */
}else{
bad++;
printf("03:sscanf( %%e) was unable to do(%s)\n",in);
};/* fi */
f = PI;
i = sscanf(in,"%E",&f);
if(i==1){
hexer_4(strhex,&f);
if(strcmp(hexf,strhex)==0){
; sprintf(strout,"%.0E",f);
; if(strcmp(outE,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,outE,hexf);
#endif
; }else{
; bad++;
; printf("04:sprintf( %%E) produced(%s), expected(%s) for(%s)\n",
strout,outE,in);
; }; /* fi */
}else{
; bad++;
; printf("05:sscanf( %%E) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexf,in);
}; /* fi */
}else{
bad++;
printf("06:sscanf( %%E) was unable to do(%s)\n",in);
};/* fi */
f = PI;
i = sscanf(in,"%f",&f);
if(i==1){
hexer_4(strhex,&f);
if(strcmp(hexf,strhex)==0){
; sprintf(strout,"%.0f",f);
; if(strcmp(outfgG,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,outfgG,hexf);
#endif
; }else{
; bad++;
; printf("07:sprintf( %%f) produced(%s), expected(%s) for(%s)\n",
strout,outfgG,in);
; }; /* fi */
}else{
; bad++;
; printf("08:sscanf( %%f) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexf,in);
}; /* fi */
}else{
bad++;
printf("09:sscanf( %%f) was unable to do(%s)\n",in);
};/* fi */
f = PI;
i = sscanf(in,"%g",&f);
if(i==1){
hexer_4(strhex,&f);
if(strcmp(hexf,strhex)==0){
; sprintf(strout,"%.0g",f);
; if(strcmp(outfgG,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,outfgG,hexf);
#endif
; }else{
; bad++;
; printf("10:sprintf( %%g) produced(%s), expected(%s) for(%s)\n",
strout,outfgG,in);
; }; /* fi */
}else{
; bad++;
; printf("11:sscanf( %%g) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexf,in);
}; /* fi */
}else{
bad++;
printf("12:sscanf( %%g) was unable to do(%s)\n",in);
};/* fi */
f = PI;
i = sscanf(in,"%G",&f);
if(i==1){
hexer_4(strhex,&f);
if(strcmp(hexf,strhex)==0){
; sprintf(strout,"%.0G",f);
; if(strcmp(outfgG,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,outfgG,hexf);
#endif
; }else{
; bad++;
; printf("13:sprintf( %%G) produced(%s), expected(%s) for(%s)\n",
strout,outfgG,in);
; }; /* fi */
}else{
; bad++;
; printf("14:sscanf( %%G) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexf,in);
}; /* fi */
}else{
bad++;
printf("15:sscanf( %%G) was unable to do(%s)\n",in);
};/* fi */
/*----------------------------- Test doubles --------------------------*/
dd = PI;
i = sscanf(in,"%le",&dd);
if(i==1){
hexer_8(strhex,&dd);
if(strcmp(hexd,strhex)==0){
; sprintf(strout,"%.0e",dd);
; if(strcmp(doute,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,doute,hexd);
#endif
; }else{
; bad++;
; printf("16:sprintf( %%e) produced(%s), expected(%s) for(%s)\n",
strout,doute,in);
; }; /* fi */
}else{
; bad++;
; printf("17:sscanf(%%le) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexd,in);
}; /* fi */
}else{
bad++;
printf("18:sscanf(%%le) was unable to do(%s)\n",in);
};/* fi */
dd = PI;
i = sscanf(in,"%lE",&dd);
if(i==1){
hexer_8(strhex,&dd);
if(strcmp(hexd,strhex)==0){
; sprintf(strout,"%.0E",dd);
; if(strcmp(doutE,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,doutE,hexd);
#endif
; }else{
; bad++;
; printf("19:sprintf( %%E) produced(%s), expected(%s) for(%s)\n",
strout,doutE,in);
; }; /* fi */
}else{
; bad++;
; printf("20:sscanf(%%lE) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexd,in);
}; /* fi */
}else{
bad++;
printf("21:sscanf(%%lE) was unable to do(%s)\n",in);
};/* fi */
dd = PI;
i = sscanf(in,"%lf",&dd);
if(i==1){
hexer_8(strhex,&dd);
if(strcmp(hexd,strhex)==0){
; sprintf(strout,"%.0f",dd);
; if(strcmp(doutfgG,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,doutfgG,hexd);
#endif
; }else{
; bad++;
; printf("22:sprintf( %%f) produced(%s), expected(%s) for(%s)\n",
strout,doutfgG,in);
; }; /* fi */
}else{
; bad++;
; printf("23:sscanf(%%lf) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexd,in);
}; /* fi */
}else{
bad++;
printf("24:sscanf(%%lf) was unable to do(%s)\n",in);
};/* fi */
dd = PI;
i = sscanf(in,"%lg",&dd);
if(i==1){
hexer_8(strhex,&dd);
if(strcmp(hexd,strhex)==0){
; sprintf(strout,"%.0g",dd);
; if(strcmp(doutfgG,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,doutfgG,hexd);
#endif
; }else{
; bad++;
; printf("25:sprintf( %%g) produced(%s), expected(%s) for(%s)\n",
strout,doutfgG,in);
; }; /* fi */
}else{
; bad++;
; printf("26:sscanf(%%lg) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexd,in);
}; /* fi */
}else{
bad++;
printf("27:sscanf(%%lg) was unable to do(%s)\n",in);
};/* fi */
dd = PI;
i = sscanf(in,"%lG",&dd);
if(i==1){
hexer_8(strhex,&dd);
if(strcmp(hexd,strhex)==0){
; sprintf(strout,"%.0G",dd);
; if(strcmp(doutfgG,strout)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,doutfgG,hexd);
#endif
; }else{
; bad++;
; printf("28:sprintf( %%G) produced(%s), expected(%s) for(%s)\n",
strout,doutfgG,in);
; }; /* fi */
}else{
; bad++;
; printf("29:sscanf(%%lG) produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexd,in);
}; /* fi */
}else{
bad++;
printf("30:sscanf(%%lG) was unable to do(%s)\n",in);
};/* fi */
dd = PI;
dd = atof(in);
if(dd!=PI){
hexer_8(strhex,&dd);
if(strcmp(hexd,strhex)==0){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,doutfgG,hexd);
#endif
}else{
; bad++;
; printf("31:atof produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexd,in);
}; /* fi */
}else{
bad++;
printf("32:atof was unable to do(%s)\n",in);
};/* fi */
dd = PI;
dd = strtod(in, &c_ptr);
if(dd!=PI){
hexer_8(strhex,&dd);
if(strcmp(hexd,strhex)==0){
; if( (c_ptr!=in) & (strch == *c_ptr) ){
; ok++;
#ifdef ECHO_GOOD
; printf("OK: (%s) -> (%s) as (%s)\n",in,doutfgG,hexd);
#endif
; }else{
; bad++;
; printf("33:strtod scanned wrong: found(%#x), expected(%#x) for(%s)\n",
(unsigned int)*c_ptr, (unsigned int)strch, in);
; }; /* fi */
}else{
; bad++;
; printf("34:strtod produced(%s) internally, expected(%s) for(%s)\n",
strhex,hexd,in);
}; /* fi */
}else{
bad++;
printf("35:strtod was unable to do(%s)\n",in);
};/* fi */
#ifdef CVT
gcvt(dd,17,strout);
if(strcmp(doutfgG,strout)==0){
ok++;
#ifdef ECHO_GOOD
printf("OK: (%s) -> (%s) as (%s)\n",in,doutfgG,hexd);
#endif
}else{
bad++;
printf("36:gcvt produced(%s), expected(%s) for(%s)\n",
strout,doutfgG,in);
}; /* fi */
#endif /* CVT */
} /* end test */
/*=====================================================================*/
main()
{
float w;
float x;
float y;
float z;
double ww;
double xx;
double yy;
double zz;
double si;
#if 0
printf("From ANSI/IEEE Standard for Radix-Independent\n");
printf("Floating-Point Arithmetic; Std. 854-1987: \n");
printf("Section 5.6 Floating-Point <-> Decimal String Conversion:\n");
printf("Overflow/underflow and NaNs and infinities encountered\n");
printf("during floating-point to decimal string conversion should\n");
printf("be indicated to the user by appropriate strings. The\n");
printf("letters 'NaN,' case insensitive, optionally preceded by\n");
printf("an algebraic sign, should be the first characters of a\n");
printf("string representing a NaN. The remainder of the string\n");
printf("may be used for system-dependent information on output,\n");
printf("and may be ignored on input. Unless recognized as a\n");
printf("quiet NaN on input, an input NaN should become a signaling\n");
printf("NaN. The letters 'inf' or 'infinity,' case insensitive,\n");
printf("optionally preceded by an algebraic sign, should be the\n");
printf("characters representing signed infinity. Either\n");
printf("representation may be produced on output; both should be\n");
printf("accepted on input.\n");
printf("To get a copy of the standards:\n");
printf(" Phone 9-1-800-678-IEEE, tell them your VISA/M.C. number.\n");
printf(" SH11460 - IEEE 854-1987 Radix-Independent Floating-Point\n");
printf(" SH10116 - IEEE 754-1985 Binary Floating-Point Arithmetic\n");
#endif
ok = bad = 0;
w = 1.0f; /* Determine how numbers are stored internally. */
byte_order = LITTLE_ENDIAN;
hexer_4( s,&w); /* convert internal to char */
if( strcmp( s, spONE ) != 0 ){
byte_order = BIG_ENDIAN;
hexer_4(ss,&w); /* convert internal to char */
if( strcmp(ss, spONE ) != 0 ){
printf("\n45: Unable to determine how numbers are stored.\n");
};
};
z = 0.0F; /* floats */
x = 1.0F/z; /* +infinity */
y = -x; /* -infinity */
w = 0.0F/z; /* -QNaN = real indefinite on a 80387 */
z = -w; /* +QNaN */
zz= 0.0; /* doubles */
xx= 1.0/zz; /* +infinity */
yy= -xx; /* -infinity */
ww= 0.0/zz; /* -QNaN = real indefinite on a 80387 */
zz= -ww; /* +QNaN */
printf("\nFirst list how infinity and Quiet-NaN are done:\n");
printf("<%9g>(%s) <%9g>(%s)\n",x,hexer_4(s,&x),xx,hexer_8(ss,&xx));
printf("<%9g>(%s) <%9g>(%s)\n",y,hexer_4(s,&y),yy,hexer_8(ss,&yy));
printf("<%9g>(%s) <%9g>(%s)\n",z,hexer_4(s,&z),zz,hexer_8(ss,&zz));
printf("<%9g>(%s) <%9g>(%s)\n",w,hexer_4(s,&w),ww,hexer_8(ss,&ww));
printf("\nCheck for support of signed NaNs:\n");
hexer_4( s,&w); /* convert internal to char */
hexer_4(ss,&z);
if( strcmp( s, ss ) == 0 ){
bad++;
printf("50:-NaNQ is same as +NaNQ, internally in float\n");
}else{
ok++;
#ifdef ECHO_GOOD
printf("OK: -NaNQ is different than +NaNQ, as a float.\n");
#endif
};
hexer_8( s,&ww); /* convert internal to char */
hexer_8(ss,&zz);
if( strcmp( s, ss ) == 0 ){
bad++;
printf("51:-NaNQ is same as +NaNQ, internally in double\n");
}else{
ok++;
#ifdef ECHO_GOOD
printf("OK: -NaNQ is different than +NaNQ, as a double.\n");
#endif
};
printf("\nCheck on NaNs of sscanf vs internal math (ignore signs):\n");
si = PI;
sscanf("-NaNQ","%le",&si);
hexer_8( s,&si); /* convert internal to char */
hexer_8(ss,&zz);
if( s[2] == 'f' ){ s[2] = '7'; }; /* absolute value */
if( ss[2] == 'f' ){ ss[2] = '7'; };
if( strcmp( s, ss ) != 0 ){
bad++;
printf("00:sscanf produced(%s) for Quiet-Nan;\n", s);
printf(" (0./0.) produced(%s)\n", ss);
}else{
ok++;
#ifdef ECHO_GOOD
printf("OK: sscanf(Quiet-Nan) == 0./0.\n");
#endif
};
printf("\nThe order of the following tests is:\n");
printf(" Mixed case, UPPER case, lower case, +case, -case\n");
#ifdef CVT
printf(" Each case is tested 13 ways:\n");
#else
printf(" Each case is tested 12 ways:\n");
#endif
printf(" sscanf/sprintf: e, E, f, g, G: float\n");
printf(" sscanf/sprintf: le, lE, lf, lg, lG: double\n");
#ifdef CVT
printf(" atof, strtod, gcvt: double\n");
#else
printf(" atof, strtod: double\n");
#endif
printf("\nINF - part of ANSI/IEEE Std. 854-1987\n");
test( "Inf",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test( "INF",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test( "inf",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test("+INF",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test("-INF",dmINF,smINF,dmInf,dmInf,dmInf,smInf,smInf,smInf,Nul);
printf("\ninfinity - part of ANSI/IEEE Std. 854-1987\n");
test( "Infinity",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test( "INFINITY",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test( "infinity",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test("+infinity",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test("-infinity",dmINF,smINF,dmInf,dmInf,dmInf,smInf,smInf,smInf,Nul);
printf("\ninfinite - part of ANSI/IEEE Std. 854-1987\n");
test( "Infinite",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,'i');
test( "INFINITE",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,'I');
test( "infinite",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,'i');
test("+infinite",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,'i');
test("-infinite",dmINF,smINF,dmInf,dmInf,dmInf,smInf,smInf,smInf,'i');
printf("\n1e999999 - another form of infinity\n");
test( "1e999999",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test( "1E999999",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test("1e+999999",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test("+1e999999",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,Nul);
test("-1e999999",dmINF,smINF,dmInf,dmInf,dmInf,smInf,smInf,smInf,Nul);
printf("\n1e4294967296 = (2**32) - another form of infinity\n");
test( "1e4294967296",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,\
Nul);
test( "1E4294967296",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,\
Nul);
test("1e+4294967296",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,\
Nul);
test("+1e4294967296",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,\
Nul);
test("-1e4294967296",dmINF,smINF,dmInf,dmInf,dmInf,smInf,smInf,smInf,\
Nul);
printf("\n1e4294967264 = (2**32 - 32) - another form of infinity\n");
test( "1e4294967264",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,\
Nul);
test( "1E4294967264",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,\
Nul);
test("1e+4294967264",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,\
Nul);
test("+1e4294967264",dpINF,spINF,dpInf,dpInf,dpInf,spInf,spInf,spInf,\
Nul);
test("-1e4294967264",dmINF,smINF,dmInf,dmInf,dmInf,smInf,smInf,smInf,\
Nul);
printf("\nNaN - part of ANSI/IEEE Std. 854-1987\n");
test( "NaN",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,Nul);
test( "NAN",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,Nul);
test( "nan",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,Nul);
test("+NaN",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,Nul);
test("-NaN",dmNANS,smNANS,dmNS,dmNS,dmNS,smNS,smNS,smNS,Nul);
printf("\nNaNS - part of ANSI/IEEE Std. 854-1987\n");
test( "NaNS",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,Nul);
test( "NANS",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,Nul);
test( "nans",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,Nul);
test("+NaNS",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,Nul);
test("-NaNS",dmNANS,smNANS,dmNS,dmNS,dmNS,smNS,smNS,smNS,Nul);
printf("\nNaNQ - part of ANSI/IEEE Std. 854-1987\n");
test( "NaNQ",dpNANQ,spNANQ,dpNQ,dpNQ,dpNQ,spNQ,spNQ,spNQ,Nul);
test( "NANQ",dpNANQ,spNANQ,dpNQ,dpNQ,dpNQ,spNQ,spNQ,spNQ,Nul);
test( "nanq",dpNANQ,spNANQ,dpNQ,dpNQ,dpNQ,spNQ,spNQ,spNQ,Nul);
test("+NaNQ",dpNANQ,spNANQ,dpNQ,dpNQ,dpNQ,spNQ,spNQ,spNQ,Nul);
test("-NaNQ",dmNANQ,smNANQ,dmNQ,dmNQ,dmNQ,smNQ,smNQ,smNQ,Nul);
printf("\nNaN() - a way to do other values of NaN\n");
test( "NaN()",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,'(');
test( "NAN()",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,'(');
test( "nan()",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,'(');
test("+NaN()",dpNANS,spNANS,dpNS,dpNS,dpNS,spNS,spNS,spNS,'(');
test("-NaN()",dmNANS,smNANS,dmNS,dmNS,dmNS,smNS,smNS,smNS,'(');
printf("\n1/0 - part of IEEE 854 draft 1.0 -- not in final standard\n");
test( "1/0",dpONE,spONE, "1", "1e+00", "1E+00", "1", "1e+00",\
"1E+00",'/');
test("1/+0",dpONE,spONE, "1", "1e+00", "1E+00", "1", "1e+00",\
"1E+00",'/');
test("1/-0",dpONE,spONE, "1", "1e+00", "1E+00", "1", "1e+00",\
"1E+00",'/');
test("+1/0",dpONE,spONE, "1", "1e+00", "1E+00", "1", "1e+00",\
"1E+00",'/');
test("-1/0",dmONE,smONE,"-1","-1e+00","-1E+00","-1","-1e+00",\
"-1E+00",'/');
printf("\n0/0 - alternate form of NaN -- not in standards.\n");
test( "0/0",dpZERO,spZERO, "0", "0e+00", "0E+00", "0", "0e+00", "0E+00",\
'/');
test("0/+0",dpZERO,spZERO, "0", "0e+00", "0E+00", "0", "0e+00", "0E+00",\
'/');
test("0/-0",dpZERO,spZERO, "0", "0e+00", "0E+00", "0", "0e+00", "0E+00",\
'/');
test("+0/0",dpZERO,spZERO, "0", "0e+00", "0E+00", "0", "0e+00", "0E+00",\
'/');
test("-0/0",dmZERO,smZERO,"-0","-0e+00","-0E+00","-0","-0e+00","-0E+00",\
'/');
printf("\n1e+ 99999 - strange form of 1.0, not infinity.\n");
test( "1e 99999", dpONE,spONE, "1", "1e+00", "1E+00", "1", "1e+00",\
"1E+00",'e');
test( "1e+ 99999",dpONE,spONE, "1", "1e+00", "1E+00", "1", "1e+00",\
"1E+00",'e');
test( "1E+ 99999",dpONE,spONE, "1", "1e+00", "1E+00", "1", "1e+00",\
"1E+00",'E');
test("+1e+ 99999",dpONE,spONE, "1", "1e+00", "1E+00", "1", "1e+00",\
"1E+00",'e');
test("-1e+ 99999",dmONE,smONE,"-1","-1e+00","-1E+00","-1","-1e+00",\
"-1E+00",'e');
printf("\n%d OK, %d bad\n",ok,bad);
}
More information about the Numeric-interest
mailing list