10 PRINT "A PARANOID PROGRAM to DIAGNOSE FLOATING-POINT ARITHMETIC" 20 PRINT "in BASIC v. A1.10 (May 1982) on the IBM Personal Computer." 30 '***** Use only one of the following two statement lines ! ***** 40 PRINT " ... Single Precision version ..." 50 ' DEFDBL A-H, O-Z : PRINT " ... Double Precision version ..." 60 '***************************************************************** 70 DEFINT I-N : I0=20 : ' ... I0 = #( random trials of X*Y=Y*X , etc.) 80 GOTO 160 90 ' This program runs interactively putting all output to a screen. The next 100 ' Subprogram pauses, allowing you to read the screen or copy it. 110 PRINT CHR$(7) : INPUT; "To continue diagnosis, press ENTER [<-'] key:",X$ 120 CLS : ' ... or HOME, or ? CHR$(12), or FOR I=1 TO 22 : PRINT : NEXT I 130 K=K+1 : PRINT "Diagnosis resumes after milestone #L =";L;", ... page";K 140 L=L+1 : PRINT : RETURN 150 ' ----------------------------------------------- 160 K=0 : L=0 : ' ... K = #( page of diagnosis ), L = Milestone in program 170 PRINT : PRINT "Lest this program stop prematurely, i.e. before displaying" 180 PRINT " ` End of Test ' ," 190 PRINT "try to persuade the computer NOT to terminate execution whenever an" 200 PRINT "`error' like Over/Underflow or Division by Zero occurs, but rather" 210 PRINT "to persevere with a surrogate value after, perhaps, displaying some" 220 PRINT "warning. If persuasion avails naught, don't despair but run this" 230 PRINT "program anyway to see how many milestones (#L) it passes, and then" 240 PRINT "amend it to make further progress. (See program lines #250 - 370.)" 250 '________ Only for Compiled BASIC on the IBM PC ________ 260 V8=0 : Q8=0 : ON ERROR GOTO 270 : GOTO 380 270 IF NOT ( ERR=5 OR ERR=6 OR ERR=11) THEN ON ERROR GOTO 0 280 IF NOT (ERR=5) THEN 320 290 IF NOT (ERL=3030 AND I=1) THEN ON ERROR GOTO 0 300 Y=-O : J1=J1+1 : PRINT S$;"BUG: If X=0 then SQR(-X) stops the machine ! 310 RESUME NEXT 320 E8=O2^63 : E8=E8*O2*F9*E8 : IF (ERR=6) THEN 340 330 Q8=O1+Q8 : Q9=E8 : B8=Q8 : PRINT "DIVISION by ZERO ..." : GOTO 350 340 V8=O1+V8 : V9=E8 : B8=V8 : PRINT "OVERFLOW ..." : IF (ERL=5530 OR ERL=5520) THEN V9=-V9 350 IF (B8>O1) THEN RESUME NEXT 360 J2=J2+1 : PRINT "were it not simulated here, it would Stop the machine! This is a DEFECT." : RESUME NEXT 370 '~~~~~~~~ end of error-handler ~~~~~~~~~ 380 PRINT 390 PRINT "Users are invited to help debug and augment this program so it will" 400 PRINT "cope with unanticipated and newly uncovered arithmetic pathologies." 410 PRINT "Please send suggestions and interesting results to the author:" 420 PRINT "*(C) 1983 Prof. W. M. Kahan, 567 Evans Hall," 430 PRINT " Apr. 19 Elect. Eng. & Computer Science Dept.," 440 PRINT " ~~~~~~~ University of California," 450 PRINT " Berkeley, Calif. 94720" 460 PRINT "* You may copy this program freely if you acknowledge its source." 470 GOSUB 110 : ' ---- PAUSE ---- 480 PRINT "Running this program should reveal these characteristics:" 490 PRINT " B = Radix ( 1, 2, 4, 8, 10, 16, 100, 256, or ... ) ." 500 PRINT " P = Precision, the number of significant B-digits carried." 510 PRINT " U2 = B/B^P = One Ulp (Unit in the Last Place) of 1.000xxx... ." 520 PRINT " U1 = 1/B^P = One Ulp of numbers a little less than 1.0 ." 530 PRINT " G1, G2, G3 tell whether adequate Guard Digits are carried;" 540 PRINT " 1 = YES , 0 = NO ; G1 for MULT., G2 for DIV., G3 for SUBT." 550 PRINT " R1, R2, R3, R4 tell whether arithmetic is rounded or chopped;" 560 PRINT " 0 = chopped, 1 = correctly rounded, -1 = some other rounding;" 570 PRINT " R1 for MULT., R2 for DIV., R3 for ADD/SUBT., R4 for SQRT." 580 PRINT " S=1 when a sticky bit is used correctly in rounding; else S=0." 590 PRINT " U0 = an underflow threshold." 600 PRINT " E0 and Z0 tell whether underflow is abrupt, gradual or fuzzy." 610 PRINT " V = an overflow threshold, roughly." 620 PRINT " V0 tells, roughly, whether Infinity is represented." 630 PRINT " Comparisons are checked for consistency with subtraction" 640 PRINT " and for contamination by pseudo-zeros." 650 PRINT " SQRT is tested. So is Y^X for (mostly) integers X ." 660 PRINT " Extra-precise subexpressions are revealed but NOT YET tested." 670 PRINT " Decimal-Binary conversion is NOT YET tested for accuracy." 680 GOSUB 110 : ' ---- PAUSE ---- 690 PRINT "The program attempts to discriminate among" 700 PRINT " FLAWs, like lack of a sticky bit, (J3)" 710 PRINT " Serious DEFECTs, like lack of a guard digit, and (J1, J2)" 720 PRINT " FAILUREs, like 2+2 = 5 . (J0)" 730 PRINT "Failures may confound subsequent diagnoses." 740 PRINT "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 750 PRINT 760 PRINT "The diagnostic capabilities of this program go beyond an earlier" 770 PRINT "program called `MACHAR' , which can be found at the end of the" 780 PRINT "book `Software Manual for the Elementary Functions' (1980) by" 790 PRINT "W. J. Cody and W. Waite. Although both programs try to discover" 800 PRINT "the radix (B), precision (P) and range (over/underflow thresholds)" 810 PRINT "of the arithmetic, this program tries to cope with a wider variety" 820 PRINT "of pathologies, and to say how well the arithmetic is implemented." 830 PRINT 840 PRINT "The program is based upon a conventional radix representation for" 850 PRINT "floating-point numbers, but also allows for logarithmic encoding" 860 PRINT "(B=1) as used by certain early WANG machines." 870 PRINT 880 L=7 : GOSUB 110 : ' ---- PAUSE ---- ===================================== 890 J0=0 : O=0 : O1=1 : PRINT "Program is now RUNNING tests on small integers:" 900 F$="FAILURE:" : V$=" Violation of " : M$=" Multiplication" 910 O2=O1+O1 : IF (O+O=O AND O1-O1=O AND O1>O AND O2=2) THEN 930 920 J0=1 : PRINT F$;V$;" 0+0=0 or 1-1=0 or 1 > 0 or 1+1 = 2 " 930 Z=-O : IF (Z=O) THEN 960 940 J0=J0+1 : PRINT F$;" Comparison alleges that Minus Zero, obtained by setting" : PRINT " X = 0 and then Z = -X , is nonzero! 950 U2=.001 : Z$="Z" : B=1 : GOSUB 4640 960 O3=O2+O1 : O4=O3+O1 : IF (O4+O2*(-O2) = O AND (O4-O3)-O1 = O) THEN 980 970 J0=J0+1 : PRINT F$;V$;" 3+1 = 2*2 " 980 F1=-O1 : IF (F1+O1=O AND O1+F1=O AND F1+ABS(F1)=O AND F1+F1*F1=O) THEN 1000 990 J0=J0+1 : PRINT F$;V$;" -1 + 1 = 0 " 1000 F2=O1/O2 : IF (F2+F1+F2=O) THEN 1020 1010 J0=J0+1 : PRINT F$;V$;" 1/2 - 1 + 1/2 = 0" 1020 L=10 : 'Miscellaneous variables: ======================================== 1030 J0=J0 : J1=0 : J2=0 : J3=0 : ' ... count FAILUREs, serious DEFECTS, FLAWS 1040 G1=O1 : G2=O1 : G3=O1 : ' ... to record guard digits 1050 A$=" Add/Subtract" : B$="correctly rounded." : C$="chopped" 1060 D$=" Division" : S$="SERIOUS " : L$=" lacks a Guard Digit, " 1070 E$=" appears to be " : H$=" is neither " : Q$="Square Root" 1080 I$=" gets too many last digits wrong." 1090 P$=" test is inconsistent; PLEASE NOTIFY THE AUTHOR !" 1100 O9=O3*O3 : T7=O9*O3 : O8=O4+O4 : T2=O4*O8 : IF (T2-T7-O4-O1=O) THEN 1120 1110 J0=J0+1 : PRINT F$;V$;" 32 - 27 - 4 - 1 = 0" 1120 O5=O4+O1 : S=O4*O5 : T=O3*O4 : T8=S*T : ' ... T8=240 1130 X=T8/O3 : Y=T8/O4 : Z=T8/O5 : X=X-O4*S : Y=Y-O5*T : Z=Z-O4*T : IF ( X=O AND Y=O AND Z=O ) THEN 1150 1140 J0=J0+1 : PRINT F$;V$;" 240/3 = 80 or 240/4 = 60 or 240/5 = 48." 1150 IF (J0=0) THEN PRINT " -1, 0, 1/2 , 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K." : PRINT 1160 PRINT "Searching for radix B and precision P ; "; 1170 W=O1 1180 W=W+W : Y=W+O1 : Z=Y-W : Y=Z-O1 : IF (F1+ABS(Y)= 1 ... 1200 P=O : Y=O1 1210 B=W+Y : Y=Y+Y : B=B-W : IF (B=O) THEN 1210 1220 IF (BX AND X>O) THEN 1320 1330 ' ... now u2 = 1 ulp of 1 + ... 1340 X=O2/O3 : F6=X-F2 : F3=F6+F6 : X=F3-F2 : X=ABS(X+F6) : IF (XX AND X>O) THEN 1360 1370 ' ... now u1 = 1 ulp of 1 - ... 1380 IF (U1=E1) THEN PRINT " confirms closest relative separation U1 ." 1390 IF (U1>O1) THEN 1630 1620 PRINT "logarithmic encoding (B=1) has precision characterized solely by U1 ." : GOTO 1650 1630 PRINT "but, by itself, this is a minor flaw." 1640 PRINT "The number of significant digits of radix B is P = "; P 1650 IF (U2*O9*O9*T8X AND X>O) THEN 1700 1710 Y=ABS( (O3/O4-O2/O3)*O3 - O1/O4 ) : Z=Y : X=Y 1720 Z1=Z : Z=(O1/O2 - ((O1/O2-(F2*Z1+T2*Z1*Z1))+O1/O2)) + O1/O2 : IF (Z1>Z AND Z>O) THEN 1720 1730 Y1=Y : Y=(F2 - ((F2-(F2*Y1+T2*Y1*Y1))+F2)) + F2 : IF (Y1>Y AND Y>O) THEN 1730 1740 X1=X : X=((F2*X1+T2*X1*X1)-F9)+F9 : IF (X1>X AND X>O) THEN 1730 1750 IF (X1=Y1 AND X1=Z1) THEN 1780 1760 J1=J1+1 : PRINT S$;"DEFECT: Disagreements among the values X1, Y1, Z1 resp." : PRINT X1;", ";Y1;", ";Z1 : PRINT "are symptoms of inconsistencies introduced by extra-precise evaluation of" 1770 PRINT "allegedly `optimized' arithmetic subexpressions. Possibly some part of this" : PRINT P$ : IF (X1=U1 OR Y1=U1 OR Z1=U1) THEN 1850 1780 IF (Z1=U1 AND Z2=U2) THEN 1870 1790 IF (Z1X) THEN X=Y 1840 Q=-LOG(X) : PRINT "Some subexpressions appear to be calculated extra-precicely with" : PRINT "about ";Q/LOG(B);" extra B-digits, i. e." : PRINT "roughly ";Q/LOG(10);" extra significant decimals." 1850 PRINT " That feature is not tested further by this program." 1860 GOSUB 110 : ' ---- PAUSE ---- 1870 L=35 : ' ================================================================ 1880 IF (BO3) THEN 2330 2320 A1 = O9+O1 : GOTO 2280 : ' Is B a power of 10 ? 2330 A1 = B : ' ... unless B is a power of A1 and A1 = 2 or 10 . 2340 A=O1/A1 : X=A1 : Y=A 2350 Z=X*Y-F2 : IF (Z=F2) THEN 2370 2360 J0=J0+1 : PRINT F$;" 1/";X;" = ";Y;", and ";X;"*(1/";X;") differs from 1." 2370 IF (X=B) THEN 2390 2380 X=B : Y=O1/X : GOTO 2350 2390 Y2=O1+U2 : Y1=O1-U2 : X=T5-U2 : Y=T5+U2 : Z=(X-U2)*Y2 : T=Y*Y1 : Z=Z-X : T=T-X : X=X*Y2 : Y=(Y+U2)*Y1 : X=X-T5 : Y=Y-T5 : IF NOT ( X=O AND Y=O AND Z=O AND T<=O ) THEN 2460 2400 X=(T5+U2)*Y2 : Y=T5-U2-U2 : Z=T5+U2+U2 : T=(T5-U2)*Y1 : X=X-(Z+U2) : S=Y*Y1 : S1=Z*Y2 : T=T-Y : Y=(U2-Y)+S : Z=S1-(Z+U2+U2) : S=(Y2+U2)*Y1 : Y1=Y2*Y1 : S=S-Y2 : Y1=Y1-F2 2410 IF ( X=O AND Y=O AND Z=O AND T=O AND S=O AND Y1=F2 ) THEN R1=O1 2420 IF ( X+U2=O AND YO OR Y>O OR Z>O OR T>O ) THEN 2540 2490 X=T5/Y2 : Y=T5-U2 : Z=T5+U2 : X=X-Y : T=T5/Y1 : Y=Y/Y1 : T=T-(Z+U2) : Y=Y-Z : Z=Z/Y2 : Y1=(Y2+U2)/Y2 : Z=Z-T5 : Y2=Y1-Y2 : Y1=(F9-U1)/F9 : IF ( X=O AND Y=O AND Z=O AND T=O AND Y2=O AND Y1-F2=F9-F2 ) THEN R2=O1 2500 IF ( XO OR T-O10 AND Z9=O) THEN 2960 2970 IF (I>0) THEN 3000 2980 X9=O1+F2/O3 : Y9=(U2+U1)+O1 : Z=X9*Y9 : Y=Y9*X9 : Z9=(O1+F2/O3)*((U2+U1)+O1)-((U2+U1)+O1)*(O1+F2/O3) : IF NOT (Z9=O) THEN 3000 2990 PRINT " ********** No failure found in ";I0;" randomly chosen pairs. **********" : GOTO 3010 3000 J2=J2+1 : PRINT "DEFECT: X*Y = Y*X violated at X = ";X9;", Y = ";Y9 : PRINT " X*Y =";Z;", Y*X =";Y;", X*Y-Y*X =";Z9 : PRINT " ... pair no.";I0-I+1 3010 L=70 : '================================================================= 3020 PRINT : PRINT "Running tests of Square Root SQR(X) :" : X=O : I=0 3030 Y=SQR(X) : IF (Y=X AND Y-F2=X-F2) THEN 3050 3040 J0=J0+1 : PRINT F$;V$;X;"= SQR(";X;"), miscalculated as";Y 3050 X=-X : I=I+1 : IF (I=1) THEN 3030 3060 X=O1 : I=I+1 : IF (I=3) THEN 3030 3070 E5=O : E7=O : GOTO 3150 : ' ... record min and max errors. 3080 ' ____ Subroutine to assess error SQRT(X*X)-X in Ulps. ____ 3090 E6=((SQR(X*X)-X*B1)-(X-X*B1))/U : IF (E6=O) THEN RETURN 3100 IF (E6E7) THEN E7=E6 3120 PRINT : J=J+1 : PRINT Z$;"DEFECT : SQR(";X*X;") - ";X;" = ";U*E6 : PRINT " instead of correct value 0 ." : RETURN 3130 ' ---- End of Sqrt(X*X)-X subroutine. ---- 3140 ' Test whether SQRT(X*X) = X ... 3150 J=0 : Z$=S$ : X=B : U=U2 : GOSUB 3090 3160 X=B1 : U=B1*U1 : GOSUB 3090 3170 X=W : U=O1 : GOSUB 3090 3180 X=U1 : U=U1*U1 : GOSUB 3090 3190 IF (J=0) THEN 3210 3200 J1=J1+J : GOSUB 110 : ' If SQRT has SERIOUS DEFECTS, then PAUSE ---- 3210 PRINT "Testing if SQR(X*X) = X for ";I0;" integers X"; 3220 J=0 : Z$="" : X=O2 : Y=B : IF (B=O1) THEN 3240 3230 X=Y : Y=B*X : IF (Y-X0) THEN 3280 3260 NEXT I 3270 PRINT " found no discrepancies." : GOTO 3290 3280 J2=J2+J 3290 ' Test SQRT for monotonicity. 3300 I=-1 : X=B9 : Y=B : Z=B+B*U2 3310 I=I+1 : X=SQR(X) : Q=SQR(Y) : Z=SQR(Z) : IF NOT (X>Q OR Q>Z) THEN 3330 3320 J2=J2+1 : PRINT "DEFECT: SQR(X) is non-monotonic for X near ";Y : GOTO 3390 3330 Q=INT(Q+F2) : IF NOT (I>0 OR Q*Q=B) THEN 3380 3340 IF (I>0) THEN 3360 3350 Y=Q : X=Y-U2 : Z=Y+U2 : GOTO 3310 3360 IF (I>1) THEN 3380 3370 Y=Y*B1 : X=Y-U1 : Z=Y+U1 : GOTO 3310 3380 PRINT "SQR has passed a test for Monotonicity." 3390 L=80 : ' Test SQRT for accuracy ...===================================== 3400 E5=E5+F2 : E7=E7-F2 : ' e5=min{error+1/2}, e7=max{error-1/2} 3410 Y=(SQR(O1+U2)-O1)/U2 : E6=(Y-O1)+U2/O8 : IF (E6>E7) THEN E7=E6 3420 E6=Y+U2/O8 : IF (E6E7) THEN E7=E6 3440 E6=(Y+O1)+U1/O8 : IF (E6E7) THEN E7=E6 3480 ON I GOTO 3500, 3520, 3500, 3530 : ' Case statement 3490 ' Cases I = 1 and 3 3500 X=U*SGN(X)*INT( O8/(O9*SQR(U)) ) : GOTO 3460 3510 ' Case I = 2 3520 U=U1 : X=-U : GOTO 3460 3530 L=85 : ' Case I = 4 exits ..... ===================================== 3540 IF (B=O1) THEN 3900 3550 PRINT"Testing whether SQR is rounded or chopped:" 3560 D=INT(F2+B^(O1+P-INT(P))) : ' ... = B^(1+fract) if P = integer + fract. 3570 X=D/B : Y=D/A1 : IF NOT (X=INT(X) AND Y=INT(Y)) THEN 3700 3580 X=O : Z2=X : Y=O1 : Y2=Y : Z1=B-O1 : D4=O4*D 3590 'Loop: for Y = 1, 3, 5, ... maximize Y2 = Y*Y mod 4D . 3600 IF NOT (Y2>Z2) THEN 3650 3610 Q=B : Y1=Y : ' ... if new Y2 > old, check that GCD(Y,B) = 1 3620 X1=ABS(Q+INT(F2-Q/Y1)*Y1) : Q=Y1 : Y1=X1 : IF (X1>O) THEN 3620 3630 IF (Q>O1) THEN 3650 : ' If GCD(Y,B) > 1 then skip over Y ; else ... 3640 Z2=Y2 : Z=Y : ' ... and GCD(Z, B) =1 3650 Y=Y+O2 : X=X+O8 : Y2=Y2+X : IF NOT (Y2O) THEN 3680 : ' else Failure! 3700 J0=J0+1 : PRINT F$;" Anomalous arithmetic with integers < B^P =";W : PRINT " foils test whether SQR rounds or chops." : GOTO 3940 3710 ' This subroutine puts NewD = B*D and NewZ^2 mod NewD = Z^2 mod D 3720 X=Z1*Q : X=INT(F2-X/B)*B+X : Q=(Q-X*Z)/B+X*X*(D/B) : Z=Z-O2*X*D : IF (Z>O) THEN 3740 3730 Z=-Z : Z1=-Z1 3740 D=B*D : RETURN : ' ___ end of NewD subroutine.___ 3750 'This Subroutine tests if SQRT(D*X)=SQRT((Y-1/2)^2+X8/2) rounds to Y .__ 3760 IF (X-BW-Z2) THEN RETURN 3770 I=I+1 : X2=SQR(X*D) : Y2=(X2-Z2)-(Y-Z2) : X2=X8/(Y-F2) : X2=X2-F2*X2*X2 : E6=(Y2+F2)+(F2-X2) : IF (E6E7) THEN E7=E6 3790 RETURN : ' ____ End of subroutine to test SQRT(D*X) = Y . ____ 3800 IF (Z1>B2) THEN Z1=Z1-B : ' -B/2 <= Z1 = 1/Z mod B <= B/2 3810 GOSUB 3720 : IF (U2*D0) THEN 3920 3910 R4=O1 : PRINT Q$;E$;B$ : GOTO 3960 3920 IF (E7+U2>U2-F2 OR E5>F2 OR E5+BM) THEN RETURN : ' ... with X = Z^M 4010 X=Z*X : IF (X0) THEN 4070 4060 J2=J2+1 : PRINT "DEFECT: Computed (";Z;")^(";Q;") =";Y : PRINT " compares Unequal to correct ";X;" ; they differ by ";Y-X 4070 N=N+1 : ' ... counts discrepancies. 4080 RETURN : ' ___ End of test subroutine. ___ 4090 ' ___ Subroutine to print count N of discrepancies. ___ 4100 IF (N>0) THEN PRINT "Similar discrepancies have occurred ";N;" times." 4110 RETURN : ' ___ End of sub. ___ 4120 N=0 : I=0 : Z=-O : M=3 : ' ... test powers of zero 4130 X=O1 : GOSUB 3980 : IF (I>10) THEN 4150 4140 I=1023 : GOSUB 3980 4150 IF (Z=F1) THEN 4170 : ' ... If (-1)^n is invalid, replace F1 by O1 ... 4160 Z=F1 : I=-4 : GOTO 4130 4170 GOSUB 4090 : ' ... print N if N>0. 4180 N1=N : N=0 : Z=A1 : M=INT( O2*LOG(W)/LOG(A1) ) 4190 X=Z : I=1 : GOSUB 3980 : IF (Z=A) THEN 4210 4200 Z=A : GOTO 4190 4210 L=100 : ' Powers of radix B have been tested; next try a few primes: == 4220 M=I0 : Z=O3 4230 X=Z : I=1 : GOSUB 3980 4240 Z=Z+O2 : IF (O3*INT(Z/O3) = Z) THEN 4240 4250 IF (Z0) THEN PRINT "Error like this may invalidate financial calculations involving interest rates." 4270 N=N+N1 : GOSUB 4280 : GOTO 4330 4280 GOSUB 4090 : ' ... print N if N>0. 4290 IF (N=0) THEN PRINT " ... no discrepancies found." 4300 PRINT 4310 IF (N>0) THEN GOSUB 110 : ' ---- PAUSE ---- 4320 RETURN : ' ___ End of printing sub. ___ 4330 L=110 : PRINT "Seeking Underflow thresholds U0 and E0 :" : '========== 4340 D=U1 : IF(P=INT(P)) THEN 4370 4350 D=B1 : X=P 4360 D=D*B1 : X=X-O1 : IF (X>O) THEN 4360 4370 Y=O1 : Z=D : ' ... D = a power of 1/B < 1 4380 C=Y : Y=Z : Z=Y*Y : IF (Y>Z AND Z+Z>Z) THEN 4380 4390 Y=C : Z=Y*D 4400 C=Y : Y=Z : Z=Y*D : IF (Y>Z AND Z+Z>Z) THEN 4400 4410 H1=B : IF (H1Z AND Z+Z>Z) THEN 4440 4450 U0=E0 : E1=O : Q=O : E9=U2 :S1=O1+E9 : D=C*S1 : IF (D>C) THEN 4490 4460 E9=B*U2 : S1=O1+E9 : D=C*S1 : IF (D>C) THEN 4490 4470 PRINT F$;M$;I$ : ' ... Multiplication is too crude 4480 J0=J0+1 : T0=E0 : Y1=O : Z0=Z : GOSUB 110 : GOTO 4570 4490 T0=D : Z0=T0*H : U0=O 4500 Y1=T0 : T0=Z0 : IF (E1+E1>E1) THEN 4520 4510 Y2=T0*H1 : E1=ABS(Y1-Y2) : Q=Y1 : IF (U0=O AND Y1>Z0 AND Z0+Z0>Z0) THEN 4500 4530 ' Now 1 >> C=1/B^(integer) >= Y > E0=Y*H >~ Z:=E0*H >~ 0 , 4540 ' and 1 >> D=(1+E9)*C >= U0 >= Q >= Y1 > T0:=Y1*H >~ Z0:=T0*H >~ 0 , 4550 ' and U0 = D/B^integer is first to violate (U0*H)/H=U0 , else U0=0 ; 4560 ' and Q:=U0/B^integer is first with E1 := |(Q*H)/H - Q| > 0, else Q=Y1. 4570 IF (Z0=O) THEN 4860 4580 ' ... Test Z0 for "phoney-zero" violating Z0O) THEN 4620 4600 J0=J0+1 : PRINT "FAILURE: Positive expressions can underflow to an allegedly negative value" : PRINT " Z0 that prints out as "; Z0 : X=-Z0 : IF (X>0) THEN 4630 4610 PRINT " But -Z0 , which should then be positive, isn't; it prints out as", X : GOTO 4630 4620 J3=J3+1 : PRINT "FLAW: Underflow can stick at an allegedly positive value Z0" : PRINT " that prints out as "; Z0 4630 GOSUB 4640 : GOTO 4860 : ' ... end of test for "phoney-zero". 4640 '___ Subroutine to test Z & Z$ for Partial Underflow ___ 4650 N=0 : IF (Z=0) THEN RETURN 4660 PRINT "Since Comparison denies ";Z$;" = 0 , evaluating (";Z$;"+";Z$;")/";Z$;" should be safe;" : PRINT "what the machine gets for (";Z$;"+";Z$;")/";Z$;" is "; : Q9=(Z+Z)/Z : PRINT Q9 : IF (ABS(Q9-O2)O2) THEN 4740 4680 N=1 : J2=J2+1 : PRINT "This is a DEFECT." : PRINT : GOTO 4760 4690 ' ___ Subroutine to test Z & Z$ for Partial Overflow ___ 4700 N=0 : PRINT "Since Comparison alleges ";Z$;" =";Z;" is finite" : PRINT "and nonzero, the next two expressions should not over/underflow:" : V9=Z*F2 4710 PRINT "The machine computes (0.5*";Z$;")/";Z$;" ="; : Q9=V9/Z : PRINT Q9 4720 PRINT "The machine computes ";Z$;"/(0.5*";Z$;") ="; : V9=Z/V9 : PRINT V9 4730 IF (ABS(Q9-F2)0=U0 , 4960 IF (U0=O) THEN I=I-2 : ' ... I=3 if E1=00 & U0>0 4970 ON I GOTO 4980, 5090, 5010, 5130 : ' ... case statement 4980 U0=T0 : IF (C1*Q = (C1*Y)*S1) THEN 5010 4990 J0=J0+1 : U0=Y : PRINT F$;"Either accuracy deteriorates as numbers approach a threshold" : PRINT "U0 =";U0;" coming down from ";C;"," : PRINT "or else ";M$;I$ : GOSUB 110 5000 ' ___ Test for X-Z = 0 although X >< Z ___ 5010 PRINT : R=SQR(T0/U0) : IF (R>H) THEN 5030 5020 Z=R*U0 : X=Z*(O1+R*H*(O1+H)) : GOTO 5040 5030 Z=U0 : X=Z*(O1+H*H*(O1+H)) 5040 IF (X=Z OR X-Z>< Z 5090 ' Case I=2 : U0 = 0 < E1 ! 5100 J0=J0+1 : PRINT F$;" Underflow confuses Comparison, which alleges that Q = Y " : PRINT " while denying that |Q-Y| = 0 ; these values print out as" : PRINT "Q =";Q;", Y =";Y2;", |Q-Y| =";ABS(Q-Y2);" ," 5110 PRINT "and Q/Y = 1 + "; (Q/Y2-F2)-F2 5120 U0=Q : GOTO 5010 5130 ' Case I=4 ; U0 > 0 & E1 > 0 5140 IF NOT (Q=U0 AND E1=E0 AND ABS(U0-E1/E9)<=E1) THEN 5010 5150 PRINT "Underflow is Gradual; it incurs Absolute error = (roundoff in U0) < E0." : Y=E0*C1 : Y=Y*(T5+U2) : X=C1*(O1+U2) : Y=Y/X : I3=0 : IF (Y=E0) THEN I3=1 : ' ... I3=1 unless gradual underflows are doubly rounded. 5160 PRINT "The Underflow threshold U0 is ";U0;" , below which" : PRINT "calculation may suffer larger Relative error than merely roundoff." 5170 Y2=U1*U1 : Y=Y2*Y2 : Y2=Y*U1 : IF (Y2>U0) THEN 5220 5180 IF (Y>E0) THEN 5200 5190 J1=J1+1 : I=4 : PRINT S$; : GOTO 5210 5200 J2=J2+1 : I=5 5210 PRINT "DEFECT: Range is too narrow; U1^";I;" underflows." 5220 L=130 : GOSUB 110 : ' ---- PAUSE ---- ================================== 5230 Y=-INT(F2-T8*LOG(U0)/LOG(H1))/T8 : Y2=Y+Y 5240 PRINT "Since Underflow occurs below the threshold U0 = (";H1;")^(";Y;") ," : PRINT "only underflow should afflict the expression (";H1;")^(";Y2;") ;" : PRINT "actually calculating it yields "; 5250 V9=H1^(Y2) : PRINT V9 : IF (V9>=O AND V9<=(B+B*E9)*U0) THEN 5270 5260 J1=J1+1 : PRINT S$; : GOTO 5300 5270 IF (V9>U0*(O1+E9)) THEN 5290 5280 PRINT " This computed value is O.K." : GOTO 5310 5290 J2=J2+1 5300 PRINT " DEFECT: this is not between 0 and U0 =";U0 5310 L=140 : PRINT : ' ====================================================== 5320 'Calculate E2 = exp(2) = 7.389056099... 5330 X=O : I=2 : Y=O2*O3 : Q=O : N=0 5340 Z=X : I=I+1 : Y=Y/(I+I) : R=Y+Q : X=Z+R : Q=(Z-X)+R : IF (X>Z) THEN 5340 5350 Z=(T5+O1/O8)+X/(T5*T2) : X=Z*Z : E2=X*X : X=F9 : Y=X-U1 5360 PRINT "Testing X^((X+1)/(X-1)) vs. exp(2) = ";E2;" as X -> 1." 5370 FOR I=1 TO I0 5380 Z=X-B1 : Z=(X+O1)/(Z-(O1-B1)) : Q=X^Z-E2 : IF (ABS(Q)>T8*U2) THEN 5420 5390 Z=(Y-X)*O2+Y : X=Y : Y=Z : IF (O1+(X-F9)*(X-F9)>O1) THEN NEXT I 5400 IF (X>O1) THEN 5440 5410 X=O1+U2 : Y=U2+U2+X : GOTO 5370 5420 N=1 : J2=J2+1 : PRINT "DEFECT: Calculated (1 + (";(X-B1)-(O1-B1);"))^(";Z;")" : PRINT " differs from correct value by ";Q 5430 PRINT "This much error may spoil financial calculations involving tiny interest rates." : GOTO 5450 5440 IF (N=0) THEN PRINT "Accuracy seems adequate." 5450 L=150 : PRINT : ' ======================================================= 5460 PRINT "Testing powers Z^Q at four nearly extreme values:" : N=0 : Z=A1 : Q=INT(F2-LOG(C)/LOG(A1)) 5470 X=C1 : GOSUB 4030 : Q=-Q : X=C : GOSUB 4030 : IF (Z(O1+B*E9)*Z) THEN 5770 5720 IF (V9>U1) THEN 5750 5730 Z$="" : J2=1+J2 : GOTO 5760 5740 PRINT Z$;"DEFECT: Comparison alleges that what prints as Z = ";Z : PRINT " is too far from SQR(Z)^2 = ";Y : RETURN 5750 Z$=S$ : J1=1+J1 5760 GOSUB 5740 5770 ON I GOTO 5780, 5790, 5800 5780 Z=E0 : GOTO 5700 5790 Z=Z0 : GOTO 5700 5800 I=0 : Z=V 5810 L=180 : '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* 5820 IF (B><2 OR P><56 OR Z0=0 OR -O=O) THEN 5850 5830 J0=1+J0 : PRINT F$;" Attempts to evaluate SQR(Overflow threshold V) in Double Precision" : PRINT "in BASIC on the IBM PC display the word ` Overflow ' and then" : PRINT "disable the Keyboard ! This is disastrous." : GOTO 5920 5840 '************************************************************************ 5850 V9=SQR(Z) : X=(O1-B*E9)*V9 : V9=V9*X : IF NOT (V9<(O1-O2*B*E9)*Z OR V9>Z) THEN 5900 5860 Y=V9 : IF (X= O1 AND X<=Y) THEN 5990 5950 IF (X*Y>=U1 AND X<=Y/U1)THEN 5970 5960 J2=J2+1 : PRINT "DEFECT: Badly "; : GOTO 5980 5970 J3=J3+1 : PRINT "FLAW: "; 5980 PRINT "unbalanced range; U0*V =";X;" is too far from 1." 5990 L=200 : ' Test X/X vs. 1. ============================================ 6000 FOR I=1 TO 5 6010 X=F9 : IF (I=2) THEN X=O1+U2 6020 IF (I=3) THEN X=V 6030 IF (I=4) THEN X=U0 6040 IF (I=5) THEN X=B 6050 Y=X : V9=(Y/X-F2)-F2 : IF (V9=0) THEN 6100 6060 X$=" X/X differs from 1 when X =" : IF (V9=-U1 AND I<5) THEN 6080 6070 J0=J0+1 : PRINT F$;X$;X : GOTO 6090 6080 J1=J1+1 : PRINT "SERIOUS DEFECT: ";X$;X 6090 PRINT " Instead, X/X - 1/2 - 1/2 = ";V9 : PRINT 6100 NEXT I 6110 L=210 : ' =============================================================== 6120 PRINT : PRINT "What messages and/or values does Division by Zero produce?" : PRINT " Trying to compute 1/0 produces ... "; : Q9=O1/O : PRINT Q9 : PRINT " Trying to compute 0/0 produces ... "; : Q9=O/O : PRINT Q9 6130 L=220 : GOSUB 110 : ' ---- PAUSE ---- =================================== 6140 N$="The number of " : T$=" The arithmetic diagnosed " : PRINT 6150 IF (J0>0) THEN PRINT N$;"FAILURES encountered = ";J0 6160 IF (J1>0) THEN PRINT N$;S$;"DEFECTS discovered = ";J1 6170 IF (J2>0) THEN PRINT N$;"DEFECTS discovered = ";J2 6180 IF (J3>0) THEN PRINT N$;"FLAWS discovered = ";J3 6190 IF (J0+J1+J2+J3>0) THEN 6270 6200 PRINT "No failures, defects nor flaws have been discovered." 6210 IF (R1+R2+R3+R40) THEN PRINT T$;"seems Satisfactory though flawed." 6280 IF (J0+J1=0 AND J2>0) THEN PRINT T$;"may be Acceptable despite inconvenient Defects." 6290 IF (J0+J1>0) THEN PRINT T$;"has unacceptable Serious Defects." 6300 IF (J0>0) THEN PRINT "Potentially fatal FAILURE may have spoiled this program's subsequent diagnoses." 6310 PRINT : PRINT "End of Test." 6320 END 6330 ' Glossary of Variables 6340 ' ~~~~~~~~~~~~~~~~~~~~~ 6350 ' A1=first of {2, 10, B} for which B = A1^(integer) , A=1/A1 6360 ' B=radix, B1=1/B, B2=B/2, B8=Q8orV8, B9=B-U2 6370 ' C=1/B^(large integer), C1=1/C 6380 ' D=C*(1+E9) or 1/B^(integer) or B^(P-integer), D4=4D 6390 ' E0=min positive, E1=..., E2=exp(2), E3=..., E5-1/2=minSQRerror, 6400 ' E6=SQRerror, E7+1/2=maxSQRerror, E8=V a priori, E9=?*U2 6410 ' F1=-1, F2=1/2, F3.=1/3, F9=1-U1 6420 ' G1=?guard*, G2=?guard/, G3=?guard- 6430 ' H=min{ 1/B, 1/2 }, H1=1/H 6440 ' I=scratch integer, I0=number of random trials X*Y=Y*X, I3=IEEE 6450 ' J=scratch, J0=#FAILUREs, J1=#SERIOUS DEFECTs, J2=#DEFECTs, J3=#FLAWs 6460 ' K=page no. of diagnosis 6470 ' L=Milestone passed in program 6480 ' M=upper bound for i in tests of Z^i 6490 ' N=0 unless Partial Over/Underflow is uncovered, N1=... 6500 ' O=0, O1=1, O2=2, O3=3, O4=4, O8=8, O9=9 6510 ' P=precision.=#Bdigits; if B=1 then P=0 6520 ' Q=scratch, Q8=#(Div. by 0), Q9=potential Divide by Zero 6530 ' R=scratch, R1=?round*, R2=?round/, R3=?round+-, R9=sqrt(3) 6540 ' S=?sticky bit, S1=... 6550 ' T=scratch, T0=underflow, T2=32, T5=1.5, T7=27, T8=240 6560 ' U=1 ulp, U0=underflow threshold, U1=1-Next(1, 0), U2=Next(1, 2)-1 6570 ' V.=overflow threshold, V0=1/0, V8=#(Overflow), V9=potential Overflow 6580 ' W=1/U1=B^P 6590 ' X=scratch, X1=..., X8=((-Z*Z)mod4D)/8, X9=random 6600 ' Y=scratch, Y1=..., Y2=..., Y9=random 6610 ' Z=scratch, Z0=pseudozero, Z1=..., Z2=Z*Zmod4D, Z9=scratch 6620 ' A$=" Add/Subtract", B$="correctly rounded.", C$="chopped" 6630 ' D$=" Division", F$="FAILURE:", I$=" gets too many last digits wrong.", 6640 ' E$=" appears to be ", H$=" is neither ", L$=" lacks a Guard Digit, " 6650 ' M$=" Multiplication", N$="The number of ", V$=" Violation of " 6660 ' P$=" test is inconsistent; PLEASE NOTIFY THE AUTHOR !" 6670 ' Q$="Square Root" 6680 ' S$="SERIOUS ", T$=" The arithmetic diagnosed ", X$=scratch, Z$=scratch 6690 '------------------------------------------------------------------