1 /* Floating point to ASCII input and output string test program.
\r
3 * Numbers in the native machine data structure are converted
\r
4 * to e type, then to and from decimal ASCII strings. Native
\r
5 * printf() and scanf() functions are also used to produce
\r
6 * and read strings. The resulting e type binary values
\r
7 * are compared, with diagnostic printouts of any discrepancies.
\r
9 * Steve Moshier, 16 Dec 88
\r
10 * last revision: 16 May 92
\r
16 /* Include tests of 80-bit long double precision: */
\r
18 /* Abort subtest after getting this many errors: */
\r
20 /* Number of random arguments to try (set as large as you have
\r
23 /* Perform internal consistency test: */
\r
24 #define CHKINTERNAL 0
\r
26 static unsigned short fullp[NE], rounded[NE];
\r
27 float prec24, sprec24, ssprec24;
\r
28 double prec53, sprec53, ssprec53;
\r
30 long double prec64, sprec64, ssprec64;
\r
33 static unsigned short rprint[NE], rscan[NE];
\r
34 static unsigned short q1[NE], q2[NE], q5[NE];
\r
35 static unsigned short e1[NE], e2[NE], e3[NE];
\r
36 static double d1, d2;
\r
37 static int errprint = 0;
\r
38 static int errscan = 0;
\r
39 static int identerr = 0;
\r
40 static int errtot = 0;
\r
41 static int count = 0;
\r
42 static char str0[80], str1[80], str2[80], str3[80];
\r
43 static unsigned short eten[NE], maxm[NE];
\r
45 int m, n, k2, mprec, SPREC;
\r
49 char *format24 = "%.8e";
\r
51 char *format53 = "%.17e";
\r
53 char *format53 = "%.16e";
\r
55 char *fformat24 = "%e";
\r
56 char *fformat53 = "%le";
\r
60 char *format64 = "%.20Le";
\r
61 char *fformat64 = "%Le";
\r
65 char *toomany = "Too many errors; aborting this test.\n";
\r
69 void chkit(), printerr(), mnrand(), etrand(), shownoncrit();
\r
70 void chkid(), pvec();
\r
76 printf( "Steve Moshier's printf/scanf tester, version 0.2.\n\n" );
\r
78 /* DEC PDP-11/VAX single precision not yet implemented */
\r
79 for( iprec = 1; iprec<2; iprec++ )
\r
81 for( iprec = 0; iprec<3; iprec++ )
\r
93 SPREC = 8; /* # digits after the decimal point */
\r
94 mprec = 24; /* # bits in the significand */
\r
95 m = 9; /* max # decimal digits for correct rounding */
\r
96 n = 13; /* max power of ten for correct rounding */
\r
97 k2 = -125; /* underflow beyond 2^-k2 */
\r
98 format = format24; /* printf format string */
\r
99 fformat = fformat24; /* scanf format string */
\r
100 mnrflag = 1; /* sets interval for random numbers */
\r
102 printf( "Testing FLOAT precision.\n" );
\r
113 fformat = fformat53;
\r
116 printf( "Testing DEC DOUBLE precision.\n" );
\r
125 fformat = fformat53;
\r
128 printf( "Testing DOUBLE precision.\n" );
\r
139 fformat = fformat64;
\r
142 printf( "Testing LONG DOUBLE precision.\n" );
\r
149 asctoe( Ten, eten );
\r
153 epow( eten, e1, maxm );
\r
154 esub( eone, maxm, maxm );
\r
157 printf( "1. Checking 10^n - 1 for n = %d to %d.\n", -m, m );
\r
159 for( count=0; count<=m; count++ )
\r
161 esub( eone, q5, fullp );
\r
163 ediv( q5, eone, q2 );
\r
164 esub( eone, q2, fullp );
\r
166 emul( eten, q5, q5 );
\r
167 if( errtot >= MAXERR )
\r
169 printf( "%s", toomany );
\r
178 printf( "2. Checking powers of 10 from 10^-%d to 10^%d.\n", n, n );
\r
180 for( count=0; count<=n; count++ )
\r
184 ediv( q5, eone, fullp );
\r
186 emul( eten, q5, q5 );
\r
187 if( errtot >= MAXERR )
\r
189 printf( "%s", toomany );
\r
197 printf( "3. Checking (10^%d-1)*10^n from n = -%d to %d.\n", m, n, n );
\r
199 for( count= -n; count<=n; count++ )
\r
201 emul( maxm, q5, fullp );
\r
204 ediv( fullp, eone, fullp );
\r
205 emul( maxm, fullp, fullp );
\r
207 emul( eten, q5, q5 );
\r
208 if( errtot >= MAXERR )
\r
210 printf( "%s", toomany );
\r
220 printf( "4. Checking powers of 2 from 2^-24 to 2^+56.\n" );
\r
223 epow( etwo, q1, q5 );
\r
225 for( count = -24; count <= 56; count++ )
\r
229 emul( etwo, q5, q5 );
\r
230 if( errtot >= MAXERR )
\r
232 printf( "%s", toomany );
\r
241 printf( "5. Checking 2^n - 1 for n = 0 to %d.\n", mprec );
\r
243 for( count=0; count<=mprec; count++ )
\r
245 esub( eone, q5, fullp );
\r
247 emul( etwo, q5, q5 );
\r
248 if( errtot >= MAXERR )
\r
250 printf( "%s", toomany );
\r
258 printf( "6. Checking 2^n + 1 for n = 0 to %d.\n", mprec );
\r
260 for( count=0; count<=mprec; count++ )
\r
262 eadd( eone, q5, fullp );
\r
264 emul( etwo, q5, q5 );
\r
265 if( errtot >= MAXERR )
\r
267 printf( "%s", toomany );
\r
276 "7. Checking %d values M * 10^N with random integer M and N,\n",
\r
278 printf(" 1 <= M <= 10^%d - 1 and -%d <= N <= +%d.\n", m, n, n );
\r
279 for( i=0; i<NRAND; i++ )
\r
283 if( errtot >= MAXERR )
\r
285 printf( "%s", toomany );
\r
293 printf("8. Checking critical rounding cases.\n" );
\r
294 for( i=0; i<20; i++ )
\r
298 if( ecmp( fullp, eone ) < 0 )
\r
299 ediv( fullp, eone, fullp );
\r
300 efloor( fullp, fullp );
\r
301 eadd( ehalf, fullp, fullp );
\r
303 if( errtot >= MAXERR )
\r
305 printf( "%s", toomany );
\r
315 printf("9. Testing on %d random non-denormal values.\n", NRAND );
\r
316 for( i=0; i<NRAND; i++ )
\r
326 "Do you want to check denormal numbers in this precision ? (y/n) " );
\r
328 if( str0[0] != 'y' )
\r
331 printf( "10. Checking denormal numbers.\n" );
\r
333 /* Form 2^-starting power */
\r
336 epow( etwo, q1, e1 );
\r
338 /* Find 2^-mprec less than starting power */
\r
341 epow( etwo, q1, e3 );
\r
342 emul( e1, e3, e3 );
\r
344 ediv( etwo, e2, e2 );
\r
346 while( ecmp(e1,e2) != 0 )
\r
348 eadd( e1, e2, fullp );
\r
353 etoe64( e1, &sprec64 );
\r
354 e64toe( &sprec64, q1 );
\r
355 etoe64( fullp, &prec64 );
\r
356 e64toe( &prec64, q2 );
\r
363 etoe53( e1, &sprec53 );
\r
364 e53toe( &sprec53, q1 );
\r
365 etoe53( fullp, &prec53 );
\r
366 e53toe( &prec53, q2 );
\r
370 etoe24( e1, &sprec24 );
\r
371 e24toe( &sprec24, q1 );
\r
372 etoe24( fullp, &prec24 );
\r
373 e24toe( &prec24, q2 );
\r
376 if( ecmp( q2, ezero ) == 0 )
\r
379 if( ecmp(q1,q2) == 0 )
\r
381 ediv( etwo, e1, e1 );
\r
384 if( errtot >= MAXERR )
\r
386 printf( "%s", toomany );
\r
389 ediv( etwo, e2, e2 );
\r
395 } /* loop on precision */
\r
396 printf( "End of test.\n" );
\r
400 long double xprec64;
\r
404 /* Check binary -> printf -> scanf -> binary identity
\r
405 * of internal routines
\r
407 void chkinternal( ref, tst, string )
\r
408 unsigned short ref[], tst[];
\r
412 if( ecmp(ref,tst) != 0 )
\r
414 printf( "internal identity compare error!\n" );
\r
415 chkid( ref, tst, string );
\r
421 /* Check binary -> printf -> scanf -> binary identity
\r
423 void chkid( print, scan, string )
\r
424 unsigned short print[], scan[];
\r
427 /* Test printf-scanf identity */
\r
428 if( ecmp( print, scan ) != 0 )
\r
431 printf( " ->printf-> %s ->scanf->\n", string );
\r
433 printf( " is not an identity.\n" );
\r
439 /* Check scanf result
\r
441 void chkscan( ref, tst, string )
\r
442 unsigned short ref[], tst[];
\r
446 if( ecmp( ref, tst ) != 0 )
\r
448 printf( "scanf(%s) -> ", string );
\r
450 printf( "\n should be " );
\r
459 /* Test printf() result
\r
461 void chkprint( ref, tst, string )
\r
462 unsigned short ref[], tst[];
\r
465 if( ecmp(ref, tst) != 0 )
\r
467 printf( "printf( ");
\r
469 printf( ") -> %s\n", string );
\r
479 /* Print array of n 16-bit shorts
\r
482 unsigned short x[];
\r
487 for( i=0; i<n; i++ )
\r
489 printf( "%04x ", x[i] );
\r
493 /* Measure worst case printf rounding error
\r
495 void cmpprint( ref, tst )
\r
496 unsigned short ref[], tst[];
\r
498 unsigned short e[NE];
\r
500 if( ecmp( ref, ezero ) != 0 )
\r
502 esub( ref, tst, e );
\r
505 if( ecmp( e, rprint ) > 0 )
\r
510 /* Measure worst case scanf rounding error
\r
512 void cmpscan( ref, tst )
\r
513 unsigned short ref[], tst[];
\r
515 unsigned short er[NE];
\r
517 if( ecmp( ref, ezero ) != 0 )
\r
519 esub( ref, tst, er );
\r
520 ediv( ref, er, er );
\r
522 if( ecmp( er, rscan ) > 0 )
\r
524 if( ecmp( er, ehalf ) > 0 )
\r
526 etoasc( tst, str1, 21 );
\r
527 printf( "Bad error: scanf(%s) = %s !\n", str0, str1 );
\r
532 /* Check rounded-down decimal string output of printf
\r
534 void cmptrunc( ref, tst )
\r
535 unsigned short ref[], tst[];
\r
537 if( ecmp( ref, tst ) != 0 )
\r
539 printf( "printf(%s%s%s, %s) -> %s\n", quo, tformat, quo, str1, str2 );
\r
540 printf( "should be %s .\n", str3 );
\r
549 etoasc( rprint, str0, 3 );
\r
550 printf( "Maximum relative printf error found = %s .\n", str0 );
\r
551 etoasc( rscan, str0, 3 );
\r
552 printf( "Maximum relative scanf error found = %s .\n", str0 );
\r
557 /* Produce arguments and call comparison subroutines.
\r
559 void chkit( testno )
\r
562 unsigned short t[NE], u[NE], v[NE];
\r
569 etoe64( fullp, &prec64 );
\r
570 e64toe( &prec64, rounded );
\r
572 e64toasc( &prec64, str1, SPREC );
\r
573 asctoe64( str1, &xprec64 );
\r
574 e64toe( &xprec64, t );
\r
575 chkinternal( rounded, t, str1 );
\r
577 /* check printf and scanf */
\r
578 sprintf( str2, format, prec64 );
\r
579 sscanf( str2, fformat, &sprec64 );
\r
580 e64toe( &sprec64, u );
\r
581 chkid( rounded, u, str2 );
\r
582 asctoe64( str2, &ssprec64 );
\r
583 e64toe( &ssprec64, v );
\r
584 chkscan( v, u, str2 );
\r
585 chkprint( rounded, v, str2 );
\r
588 /* rounding error measurement */
\r
589 etoasc( fullp, str0, 24 );
\r
590 etoe64( fullp, &ssprec64 );
\r
591 e64toe( &ssprec64, u );
\r
592 sprintf( str2, format, ssprec64 );
\r
595 sscanf( str0, fformat, &sprec64 );
\r
596 e64toe( &sprec64, t );
\r
597 cmpscan( fullp, t );
\r
600 /* strings rounded to less than maximum precision */
\r
601 e64toasc( &ssprec64, str1, 24 );
\r
602 for( j=SPREC-1; j>0; j-- )
\r
604 e64toasc( &ssprec64, str3, j );
\r
606 sprintf( tformat, "%s.%dLe", pct, j );
\r
607 sprintf( str2, tformat, ssprec64 );
\r
617 etoe53( fullp, &prec53 );
\r
618 e53toe( &prec53, rounded );
\r
620 e53toasc( &prec53, str1, SPREC );
\r
621 asctoe53( str1, &xprec53 );
\r
622 e53toe( &xprec53, t );
\r
623 chkinternal( rounded, t, str1 );
\r
625 sprintf( str2, format, prec53 );
\r
626 sscanf( str2, fformat, &sprec53 );
\r
627 e53toe( &sprec53, u );
\r
628 chkid( rounded, u, str2 );
\r
629 asctoe53( str2, &ssprec53 );
\r
630 e53toe( &ssprec53, v );
\r
631 chkscan( v, u, str2 );
\r
632 chkprint( rounded, v, str2 );
\r
635 /* rounding error measurement */
\r
636 etoasc( fullp, str0, 24 );
\r
637 etoe53( fullp, &ssprec53 );
\r
638 e53toe( &ssprec53, u );
\r
639 sprintf( str2, format, ssprec53 );
\r
642 sscanf( str0, fformat, &sprec53 );
\r
643 e53toe( &sprec53, t );
\r
644 cmpscan( fullp, t );
\r
647 e53toasc( &ssprec53, str1, 24 );
\r
648 for( j=SPREC-1; j>0; j-- )
\r
650 e53toasc( &ssprec53, str3, j );
\r
652 sprintf( tformat, "%s.%de", pct, j );
\r
653 sprintf( str2, tformat, ssprec53 );
\r
660 etoe24( fullp, &prec24 );
\r
661 e24toe( &prec24, rounded );
\r
663 e24toasc( &prec24, str1, SPREC );
\r
664 asctoe24( str1, &xprec24 );
\r
665 e24toe( &xprec24, t );
\r
666 chkinternal( rounded, t, str1 );
\r
668 sprintf( str2, format, prec24 );
\r
669 sscanf( str2, fformat, &sprec24 );
\r
670 e24toe( &sprec24, u );
\r
671 chkid( rounded, u, str2 );
\r
672 asctoe24( str2, &ssprec24 );
\r
673 e24toe( &ssprec24, v );
\r
674 chkscan( v, u, str2 );
\r
675 chkprint( rounded, v, str2 );
\r
678 /* rounding error measurement */
\r
679 etoasc( fullp, str0, 24 );
\r
680 etoe24( fullp, &ssprec24 );
\r
681 e24toe( &ssprec24, u );
\r
682 sprintf( str2, format, ssprec24 );
\r
685 sscanf( str0, fformat, &sprec24 );
\r
686 e24toe( &sprec24, t );
\r
687 cmpscan( fullp, t );
\r
692 e24toasc( &ssprec24, str1, 24 );
\r
693 for( j=SPREC-1; j>0; j-- )
\r
695 e24toasc( &ssprec24, str3, j );
\r
697 sprintf( tformat, "%s.%de", pct, j );
\r
698 sprintf( str2, tformat, ssprec24 );
\r
709 if( (errscan == 0) && (identerr == 0) && (errprint == 0) )
\r
710 printf( "No errors found.\n" );
\r
713 printf( "%d binary -> decimal errors found.\n", errprint );
\r
714 printf( "%d decimal -> binary errors found.\n", errscan );
\r
716 errscan = 0; /* reset for next test */
\r
723 /* Random number generator
\r
724 * in the range M * 10^N, where 1 <= M <= 10^17 - 1
\r
725 * and -27 <= N <= +27. Test values of M are logarithmically distributed
\r
726 * random integers; test values of N are uniformly distributed random integers.
\r
729 static char *fwidth = "1.036163291797320557783096e1"; /* log(sqrt(10^9-1)) */
\r
730 static char *dwidth = "1.957197329044938830915E1"; /* log(sqrt(10^17-1)) */
\r
731 static char *ldwidth = "2.302585092994045684017491e1"; /* log(sqrt(10^20-1)) */
\r
733 static char *a13 = "13.0";
\r
734 static char *a27 = "27.0";
\r
735 static char *a34 = "34.0";
\r
736 static char *a10m13 = "1.0e-13";
\r
737 static unsigned short LOW[ NE ], WIDTH[NE], e27[NE], e10m13[NE];
\r
740 void mnrand( erand )
\r
741 unsigned short erand[];
\r
743 unsigned short ea[NE], em[NE], en[NE], ex[NE];
\r
750 asctoe( ldwidth, WIDTH );
\r
751 asctoe( a34, e27 );
\r
755 asctoe( dwidth, WIDTH );
\r
756 asctoe( a27, e27 );
\r
760 asctoe( fwidth, WIDTH );
\r
761 asctoe( a13, e27 );
\r
763 asctoe( a10m13, e10m13 );
\r
767 e53toe( &x, ex ); /* x = WIDTH * ( x - 1.0 ) + LOW; */
\r
768 esub( eone, ex, ex );
\r
769 emul( WIDTH, ex, ex );
\r
770 eexp( ex, ex ); /* x = exp(x); */
\r
774 emul( ea, ex, ea ); /* a = 1.0e-13 * x * a; */
\r
775 emul( e10m13, ea, ea );
\r
777 eadd( ea, ex, ex ); /* add fuzz */
\r
778 emul( ex, ex, ex ); /* square it, to get range to 10^17 - 1 */
\r
779 efloor( ex, em ); /* this is M */
\r
781 /* Random power of 10 */
\r
784 esub( eone, ex, ex ); /* y3 = 54.0 * ( y3 - 1.0 ) + 0.5; */
\r
785 emul( e27, ex, ex );
\r
786 eadd( ex, ex, ex );
\r
787 eadd( ehalf, ex, ex );
\r
788 efloor( ex, ex ); /* y3 = floor( y3 ) - 27.0; */
\r
789 esub( e27, ex, en ); /* this is N */
\r
790 epow( eten, en, ex );
\r
791 emul( ex, em, erand );
\r
795 char *ldemin = "-1.1355137111933024058873097E4";
\r
796 char *ldewid = "2.2710274223866048117746193E4";
\r
798 char *demin = "-7.0839641853226410622441123E2";
\r
799 char *dewid = "1.4167928370645282124488225E3";
\r
801 char *femin = "-8.6643397569993163677154015E1";
\r
802 char *fewid = "1.7328679513998632735430803E2";
\r
804 void etrand( erand )
\r
805 unsigned short erand[];
\r
807 unsigned short ea[NE], ex[NE];
\r
814 asctoe( ldemin, LOW );
\r
815 asctoe( ldewid, WIDTH );
\r
816 asctoe( a34, e27 );
\r
820 asctoe( demin, LOW );
\r
821 asctoe( dewid, WIDTH );
\r
822 asctoe( a27, e27 );
\r
826 asctoe( femin, LOW );
\r
827 asctoe( fewid, WIDTH );
\r
828 asctoe( a13, e27 );
\r
830 asctoe( a10m13, e10m13 );
\r
834 e53toe( &x, ex ); /* x = WIDTH * ( x - 1.0 ) + LOW; */
\r
835 esub( eone, ex, ex );
\r
836 emul( WIDTH, ex, ex );
\r
837 eadd( LOW, ex, ex );
\r
838 eexp( ex, ex ); /* x = exp(x); */
\r
844 emul( ea, ex, ea ); /* a = 1.0e-13 * x * a; */
\r
845 emul( e10m13, ea, ea );
\r
846 if( ecmp( ex, ezero ) > 0 )
\r
848 eadd( ea, ex, erand );
\r