you make it right; I'll make it fast

David Hough sun!Eng!dgh
Tue Jun 12 14:46:39 PDT 1990


The first order of business for me working at home 
is to get my base conversion correctness program into distributable form.
Anyway I extracted some test cases that I found by running it on our M/2000
which has 2.0 compilers, and put them into this test program:

test(s)
char *s ;

{
double x,atof(),strtod();
int e ;
extern errno;
long unsigned * pl;

pl=(long unsigned *) &x;
errno=0;
x=atof(s);
e=errno;
printf("   atof x %g %8X %8X errno %d s %s\n",x,pl[0],pl[1],e,s);
errno=0;
x=strtod(s,0);
e=errno;
printf(" strtod x %g %8X %8X errno %d s %s\n",x,pl[0],pl[1],e,s);
errno=0;
(void) sscanf(s,"%lf",&x);
e=errno;
printf(" sscanf x %g %8X %8X errno %d s %s\n",x,pl[0],pl[1],e,s);
}

main()
{
test("1.e+126");
test("1.0e+126");
test("-100000000000000000000000000000000000000000000000000000000000000");
test("-100000000000000000000000000000000000000000000000000000000000000.0");
test("-0999999999999999999999999999999999999999999999999999999");
test("-999999999999999999999999999999999999999999999999999999.0");
test("-836856653383323110000000000000000000000000000000000000000000000000000000000000000000000000.0000");
}

MIPS' conversion routines are pretty accurate for two man-weeks of effort
but not above criticism, in my view.  
Some of you may not consider all of these tests to be legitimate or interesting; 
anyway compiling cc testmips.c and running yields

   atof x 1e+126 5A17A2EC C414A040 errno 0 s 1.e+126
 strtod x 1e+126 5A17A2EC C414A041 errno 0 s 1.e+126
 sscanf x 1e+126 5A17A2EC C414A040 errno 9 s 1.e+126
   atof x 1e+126 5A17A2EC C414A03F errno 0 s 1.0e+126
 strtod x 1e+126 5A17A2EC C414A041 errno 0 s 1.0e+126
 sscanf x 1e+126 5A17A2EC C414A03F errno 9 s 1.0e+126
   atof x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000
 strtod x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000
 sscanf x -1e+62 CCCF1D75 A5709C1B errno 34 s -100000000000000000000000000000000000000000000000000000000000000
   atof x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000.0
 strtod x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000.0
 sscanf x -1e+62 CCCF1D75 A5709C1B errno 34 s -100000000000000000000000000000000000000000000000000000000000000.0
   atof x -1e+54 CB24E187 8814C9CD errno 0 s -0999999999999999999999999999999999999999999999999999999
 strtod x -1e+54 CB24E187 8814C9CE errno 0 s -0999999999999999999999999999999999999999999999999999999
 sscanf x -1e+54 CB24E187 8814C9CD errno 9 s -0999999999999999999999999999999999999999999999999999999
   atof x -1e+54 CB24E187 8814C9CD errno 0 s -999999999999999999999999999999999999999999999999999999.0
 strtod x -1e+54 CB24E187 8814C9CE errno 0 s -999999999999999999999999999999999999999999999999999999.0
 sscanf x -1e+54 CB24E187 8814C9CD errno 9 s -999999999999999999999999999999999999999999999999999999.0
   atof x -8.36857e+89 D29A4AE3 2080FA81 errno 0 s -836856653383323110000000000000000000000000000000000000000000000000000000000000000000000000.0000
 strtod x -8.36857e+89 D29A4AE3 2080FA82 errno 0 s -836856653383323110000000000000000000000000000000000000000000000000000000000000000000000000.0000
 sscanf x -8.36857e+89 D29A4AE3 2080FA82 errno 34 s -836856653383323110000000000000000000000000000000000000000000000000000000000000000000000000.0000

which might be good enough for many purposes; compiling on a Sun-4
with our C 1.0 product this way:

 /usr/lang/SC0.0/cc  testmips.c -u _fix_libc_

(we don't distribute libc with C 1.0; the -u _fix_libc_ causes necessary patches
 to be picked up from libm which we do distribute with C 1.0)

produces

   atof x 1e+126 5A17A2EC C414A03F errno 0 s 1.e+126
 strtod x 1e+126 5A17A2EC C414A03F errno 0 s 1.e+126
 sscanf x 1e+126 5A17A2EC C414A03F errno 0 s 1.e+126
   atof x 1e+126 5A17A2EC C414A03F errno 0 s 1.0e+126
 strtod x 1e+126 5A17A2EC C414A03F errno 0 s 1.0e+126
 sscanf x 1e+126 5A17A2EC C414A03F errno 0 s 1.0e+126
   atof x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000
 strtod x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000
 sscanf x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000
   atof x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000.0
 strtod x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000.0
 sscanf x -1e+62 CCCF1D75 A5709C1B errno 0 s -100000000000000000000000000000000000000000000000000000000000000.0
   atof x -1e+54 CB24E187 8814C9CE errno 0 s -0999999999999999999999999999999999999999999999999999999
 strtod x -1e+54 CB24E187 8814C9CE errno 0 s -0999999999999999999999999999999999999999999999999999999
 sscanf x -1e+54 CB24E187 8814C9CE errno 0 s -0999999999999999999999999999999999999999999999999999999
   atof x -1e+54 CB24E187 8814C9CE errno 0 s -999999999999999999999999999999999999999999999999999999.0
 strtod x -1e+54 CB24E187 8814C9CE errno 0 s -999999999999999999999999999999999999999999999999999999.0
 sscanf x -1e+54 CB24E187 8814C9CE errno 0 s -999999999999999999999999999999999999999999999999999999.0
   atof x -8.36857e+89 D29A4AE3 2080FA81 errno 0 s -836856653383323110000000000000000000000000000000000000000000000000000000000000000000000000.0000
 strtod x -8.36857e+89 D29A4AE3 2080FA81 errno 0 s -836856653383323110000000000000000000000000000000000000000000000000000000000000000000000000.0000
 sscanf x -8.36857e+89 D29A4AE3 2080FA81 errno 0 s -836856653383323110000000000000000000000000000000000000000000000000000000000000000000000000.0000

which some people might prefer on consistency grounds if no others.
Which is more accurate?  bc isn't good for much as a systems benchmark,
but it comes in handy here:

kcng% bc
obase=16
10^54
A70C3C40A64E6C51999090B65F67D9240000000000000
(10^54)*2
14E1878814C9CD8A33321216CBECFB2480000000000000

The latter form is convenient for comparison with IEEE double precision format.
Clearly 
14E1878814C9CE000...
is a better approximation (ie correctly rounded) to
14E1878814C9CD8A33321216CBECFB2480000000000000
than
14E1878814C9CD000...

Similarly 
(10^126)*4
17A2ECC414A03F7FF6CA1CB527787B130A97D51E51202365498FF69BE1291D6C857CBE\
4A2900000000000000000000000000000000

tells a similar story.

It took me quite a bit longer than two weeks - more like two months elapsed
time - to get the test program that found these examples working well; the
code that produces the correctly-rounded results quite a bit longer than that. 
Regardless of one's opinion of bc,
I believe that the Sun results indicated are indeed correctly rounded.

Richard Tuck relates that it took him about six weeks elapsed time to write
up the 68010 assembly code for the base conversion in SunOS 3.x.



More information about the Numeric-interest mailing list