10 PRINT "A PARANOID PROGRAM to DIAGNOSE FLOATING-POINT ARITHMETIC" 20 PRINT "in BASIC v. A1.11 (2020) on the IBM Personal Computer." 23 ' JTC: changes in v. A1.11 are marked JTC in lines numbered xxxx3. 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$ 113 ' JTC: removed unneeded '-character from [<-] in 110 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 933 ' JTC: Add double-quote to close the latter string on 940. 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)<O) THEN 1180 1190 '... now W is just big enough that |((W+1)-W)-1| >= 1 ... 1200 P=O : Y=O1 1210 B=W+Y : Y=Y+Y : B=B-W : IF (B=O) THEN 1210 1220 IF (B<O2) THEN B=O1 1230 PRINT " Radix B = "; B : IF (B=O1) THEN 1270 :' ... else B >= 2 ... 1240 W=O1 1250 P=P+O1 : W=W*B : Y=W+O1 : Z=Y-W : IF (Z=O1) THEN 1250 1260 ' ... now W = B^P is barely too big to satisfy (W+1)-W = 1 ... 1270 U1=O1/W : U2=B*U1 : PRINT "Closest relative separation found is U1 ="; U1 1280 PRINT : PRINT "Recalculating radix and precision "; 1290 E0=B : E1=U1 : E9=U2 : E3=P :' ... save old values 1300 X=O4/O3 : F3=X-O1 : F6=F2-F3 : X=F6+F6 : X=ABS(X-F3) : IF (X<U2) THEN X=U2 1310 ' ... now x = (unknown no.) ulps of 1 + ... 1320 U2=X : Y=F2*U2+T2*U2*U2 : Y=O1+Y : X=Y-O1 : IF (U2>X 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 (X<U1) THEN X=U1 1350 ' ... now x = (unknown no.) ulps of 1 - ... 1360 U1=X : Y=F2*U1+T2*U1*U1 : Y=F2-Y : X=F2+Y : Y=F2-X : X=F2+Y : IF (U1>X 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<>E1) THEN PRINT " gets better closest relative separation U1 = "; U1 1393 ' JTC: change all instances of >< for "not equal" to <> 1400 W=O1/U1 : F9=(F2-U1)+F2 : ' ... = 1 - U1 = nextafter(1.0, 0) 1410 B=INT(.01 + U2/U1) : IF (B=E0) THEN PRINT "Radix B confirmed." 1420 IF (B<>E0) THEN PRINT "MYSTERY: recalculated radix B = "; B 1430 IF (B=O2 OR B-O9=O1 OR B=O1) THEN 1470 1440 IF (B>O8+O8) THEN 1460 1450 J3=J3+1 : PRINT "FLAW: Radix B =";B;" is not so good as 2 or 10." : GOTO 1470 1460 J2=J2+1 : PRINT "DEFECT: Radix B =";B;" is so big that roundoff propagates capriciously." 1470 L=20 : ' Test for fuzzy comparison ... ================================== 1480 IF (F9-F2<F2) THEN 1510 1490 J0=J0+1 1500 PRINT F$;" (1-U1)-1/2 < 1/2 is FALSE, so this program may malfunction." 1510 X=F9 : I=1 1520 Y=X-F2 : Z=Y-F2 : IF (X<>O1 OR Z=O) THEN 1540 1530 J0=J0+1 : PRINT F$;" Comparison is fuzzy; it alleges X = 1 although" : PRINT " subtraction yields (X - 1/2) - 1/2 = ";Z 1540 IF (I=0) THEN 1560 1550 X=O1+U2 : I=0 : GOTO 1520 1560 L=25 : ' End of test for fuzzy comparison.=============================== 1570 B9=B-O1 : B9=(B9-U2)+O1 : IF (B=O1) THEN 1610 : ' ... B9 = nextafter(B, 0) 1580 X=-T8*LOG(U1)/LOG(B) : Y=INT(F2+X) : IF ( ABS(X-Y)*O4<O1 ) THEN X=Y 1590 P=X/T8 : Y=INT(F2+P) : IF ( ABS(P-Y)*T8<F2 ) THEN P=Y : ' Purify integers. 1600 IF (P=INT(P)) THEN 1640 1610 PRINT "Precision cannot be characterized by an integer number of sig. digits;" : IF (B>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*T8<O1) THEN 1670 1660 J1=J1+1 : PRINT S$;"DEFECT: Precision worse than 5 sig. dec. is usually inadequate." : GOTO 1680 1670 PRINT 1680 L=30 : 'Test for extra-precise subexpressions: ======================== 1690 X=ABS( ((O4/O3-O1)-O1/O4)*O3 - O1/O4 ) 1700 Z2=X : X=(O1+(F2*Z2+T2*Z2*Z2))-O1 : IF (Z2>X 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 (Z1<U1 AND Z2<U2) THEN 1810 1800 J0=J0+1 : PRINT F$;"Precision";P$ : PRINT "U1 =";U1;", Z1-U1 =";Z1-U1 : PRINT "U2 =";U2;", Z2-U2 =";Z2-U2 : GOTO 1860 1810 IF (Z1>O AND Z2>O) THEN 1830 1820 PRINT "Because of an unusual radix B =";B;", or exact rational arithmetic," : PRINT "a result Z1 =";Z1;" or Z2 =";Z2;" of an extra-precision" : PRINT P$ : IF (Z1=Z2) THEN 1850 1830 X=Z1/U1 : Y=Z2/U2 : IF (Y>X) 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 (B<O2) THEN 1920 1890 X=W/(B*B) : Y=X+O1 : Z=Y-X : T=Z+U2 : X=T-Z : IF (X=U2) THEN 1910 1900 J0=J0+1 : PRINT F$;" Subtraction is not normalized, so X=Y does not imply X+Z=Y+Z !" : GOTO 1920 1910 PRINT "Subtraction appears to be normalized, as it should." 1920 PRINT 1930 PRINT "Checking for guard digit in Multiply (G1), Divide (G2) and Subtract (G3) :" 1940 Y=F9*O1 : Z=O1*F9 : X=F9-F2 : Y=(Y-F2)-X : Z=(Z-F2)-X : X=O1+U2 : T=X*B 1950 R=B*X : X=T-B : X=X-B*U2 : T=R-B : T=T-B*U2 : X=X*(B-O1) : T=T*(B-O1) : IF (X=O AND Y=O AND Z=O AND T=O) THEN 1980 1960 J1=J1+1 1970 G1=O : PRINT S$;"DEFECT:";M$;L$;"violating 1*X = X ." 1980 Z=B*U2 : X=O1+Z : Y=ABS((X+Z)-X*X)-U2 : X=O1-U2 : Z=ABS((X-U2)-X*X)-U1 : IF (Y<=O AND Z<=O) THEN 2000 1990 J0=J0+1 : PRINT F$;M$;I$ 2000 Y=O1-U2 : X=O1+U2 : Z=O1/Y : Y=Z-X : X=O1/O3 : Z=O3/O9 : X=X-Z : T=O9/T7 2010 Z=Z-T : IF (X=O AND Y=O AND Z=O) THEN 2040 2020 J2=J2+1 2030 G2=O : PRINT "DEFECT:";D$;L$;"so error can exceed 1 ulp" : PRINT "or 1/3 and 3/9 and 9/27 may disagree." 2040 Y=F9/O1 : X=F9-F2 : Y=(Y-F2)-X : X=O1+U2 : T=X/O1 : X=T-X : IF (X=O AND Y=O) THEN 2070 2050 J1=J1+1 : J2=J2-1+G2 2060 G2=O : PRINT S$;"DEFECT:";D$;L$;"violating X/1 = X ." 2070 X=O1/(O1+U2) : Y=X-F2-F2 : IF (Y<O) THEN 2100 2080 J1=J1+1 2090 PRINT "VERY SERIOUS DEFECT: Computed value of 1/1.00...001 is not less than 1 ." 2100 X=O1-U2 : Y=O1+B*U2 : Z=X*B : T=Y*B : R=Z/B : S=T/B : X=R-X : Y=S-Y : IF (X=O AND Y=O) THEN 2130 2110 J0=J0+1 2120 PRINT F$;M$;" and/or";D$;I$ 2130 Y=O1-U1 : X=O1-F9 : Y=O1-Y : T=B-U2 : Z=B-B9 : T=B-T 2140 IF (X=U1 AND Y=U1 AND Z=U2 AND T=U2) THEN 2230 2150 J1=J1+1 2160 G3=O : PRINT S$;"DEFECT: Subtraction";L$;"so cancellation is obscured." 2170 IF (F9=O1 OR F9-O1<O) THEN 2240 2180 J1=J1+1 2190 PRINT "VERY SERIOUS DEFECT: comparison alleges (1-U1) < 1 although" 2200 PRINT " subtraction yields (1-U1) - 1 = 0 , thereby vitiating" 2210 PRINT " such precautions against division by zero as" 2220 PRINT " ... if (X=1.0) then ..... else .../(X-1.0)..." 2230 IF(G1*G2*G3=O1) THEN PRINT " These operations appear to have guard digits, as they should." 2240 L=40 : GOSUB 110 : ' ---- PAUSE ---- ==================================== 2250 PRINT "Checking for rounding in Multiply (R1), Divide (R2) and Add/Subtract (R3):" 2260 R1=F1 : R2=F1 : R3=F1 : B2=B/O2 : T5=O1+F2 : ' ... B2 = B/2 , T5 = 1.5 2270 A1=O2 : ' Is B a power of 2 or 10 ? 2280 A=B 2290 X=A : A=A/A1 : IF (INT(A)=A) THEN 2290 2300 IF (X=O1) THEN 2340 : ' ... B is a power of A1 ; if B=1 then A1=2. 2310 IF (A1>O3) 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 Y<O AND Z+U2=O AND T<O AND S+U2=O AND Y1<F2 ) THEN R1=O 2430 IF (R1=O) THEN PRINT " R1=0:";M$;E$;C$;"." 2440 IF (R1=O1) THEN PRINT " R1=1:";M$;E$;B$ 2450 IF (R1-G1=O1) THEN PRINT F$;M$;P$ 2460 IF (R1=F1) THEN PRINT M$;H$;C$;" nor ";B$ 2470 L=45 : ' ================================================================ 2480 Y2=O1+U2 :Y1=O1-U2 : Z=T5+U2+U2 : X=Z/Y2 : T=T5-U2-U2 : Y=(T-U2)/Y1 : Z=(Z+U2)/Y2 : X=X-T5 : Y=Y-T : T=T/Y1 : Z=Z-(T5+U2) : T=(U2-T5)+T : IF ( X>O 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 ( X<O AND Y<O AND Z<O AND T<O AND Y2<O AND Y1-F2<F9-F2 ) THEN R2=O 2510 IF (R2=O) THEN PRINT " R2=0:";D$;E$;C$;"." 2520 IF (R2=O1) THEN PRINT " R2=1:";D$;E$;B$ 2530 IF (R2-G2=O1) THEN PRINT F$;D$;P$ 2540 IF (R2=F1) THEN PRINT D$;H$;C$;" nor ";B$ 2550 B1=O1/B : IF (B1*B-F2=F2) THEN 2580 2560 J0=J0+1 2570 PRINT F$;" B*(1/B) differs from 1." 2580 L=50 : '================================================================= 2590 IF ( (F9+U1)-F2 = F2 AND (B9+U2)-O1 = B-O1 ) THEN 2610 2600 J0=J0+1 : PRINT F$;" Incomplete carry-propagation in Addition." 2610 X=O1-U1*U1 : Y=O1+U2*(O1-U2) : Z=F9-F2 : X=(X-F2)-Z : Y=Y-O1 2620 IF (X<>O OR Y<>O) THEN 2640 2630 R3=O : PRINT " R3=0:";A$;E$;C$;"." 2640 IF (G3=O) THEN 2710 2650 X=(F2+U2)*U2 : Y=(F2-U2)*U2 : X=O1+X : Y=O1+Y : X=(O1+U2)-X : Y=O1-Y 2660 IF (X<>O OR Y<>O) THEN 2710 2670 X=(F2+U2)*U1 : Y=(F2-U2)*U1 : X=O1-X : Y=O1-Y : X=F9-X : Y=O1-Y 2680 IF (X<>O OR Y<>O) THEN 2710 2690 R3=F1-O2*R3 : PRINT " R3=1:";A$;E$;B$ 2700 IF (R3-G3=O1) THEN PRINT F$;A$;P$ 2710 IF R3=F1 THEN PRINT A$;H$;C$;" nor ";B$ 2720 S1=O1 : X=O1+F2*(O1+F2) : Y=(O1+U2)*F2 : Z=X-Y : T=Y-X : S=Z+T 2730 IF (S=0) THEN 2770 2740 S1=O : J3=J3+1 2750 PRINT "FLAW: Nonzero (X-Y)+(Y-X) =";S;" when" 2760 PRINT " X =";X;" and Y =";Y 2770 S=O : IF (G1*G2*G3<O1 OR R1<O1 OR R2<O1 OR R3<O1 OR INT(B2)<>B2) THEN 2890 2780 PRINT : PRINT "Checking for sticky bit (S)." 2790 X=(F2+U1)*U2 : Y=F2*U2 : Z=O1+Y : T=O1+X : IF (Z-O1>O OR T-O1<U2)THEN 2890 2800 Z=T+Y : Y=Z-X : IF (Z-T<U2 OR Y-T<>O) THEN 2890 2810 X=(F2+U1)*U1 : Y=F2*U1 : Z=O1-Y : T=O1-X : IF (Z-O1<>O OR T-F9<>O) THEN 2890 2820 Z=(F2-U1)*U1 : T=F9-Z : Q=F9-Y : IF (T-F9<>O OR (F9-U1)-Q<>O) THEN 2890 2830 Z=(O1+U2)*T5 : T=(T5+U2)-Z+U2 : X=O1+F2/B : Y=O1+B*U2 : Z=X*Y 2840 IF (T<>O OR (X+B*U2)-Z<>O) THEN 2890 2850 IF (B=O2) THEN 2870 2860 X=O2+U2 : Y=X/O2 : IF (Y-O1<>O) THEN 2890 2870 S=S1 2880 IF (S=O1) THEN PRINT " S=1: Sticky bit";E$;"used correctly." 2890 IF (S=O) THEN PRINT " S=0: Sticky bit used incorrectly or not at all." 2900 IF (G1*G2*G3=O OR R1<O OR R2<O OR R3<O) THEN J3=J3+1 2910 L=60 : '================================================================= 2920 PRINT : PRINT "Does Multiplication commute? Testing if X*Y = Y*X for";I0;"random pairs:" 2930 R9=SQR(3) : I=I0+1 : X9=O1/O3 : GOTO 2960 2940 ' ____ Random Number Generator ____ 2950 X=X9+R9 : Y=X*X : Y=Y*Y : X=X*Y : Y=X-INT(X) : X9=Y+X*.000005 : RETURN 2960 GOSUB 2950 : Y9=X9 : GOSUB 2950 : Z=X9*Y9 : Y=Y9*X9 : Z9=Z-Y : I=I-1 : IF (I>0 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 (E6<E5) THEN E5=E6 3110 IF (E6>E7) 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-X<I0) THEN 3230 3240 U=X*U2 : FOR I=1 TO I0 3250 X=X+O1 : GOSUB 3090 : IF (J>0) 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 (E6<E5) THEN E5=E6 3430 Y=((SQR(F9)-U2)-(O1-U2))/U1 : E6=Y+U1/O8 : IF (E6>E7) THEN E7=E6 3440 E6=(Y+O1)+U1/O8 : IF (E6<E5) THEN E5=E6 3450 I=0 : U=U2 : X=U 3460 I=I+1 : Y=SQR((X+U1+X)+F9) : Y=((Y-U2)-((O1-U2)+X))/U : Z=((U1-X)+F9)*F2*X*X/U : E6=(Y+F2)+Z : IF (E6<E5) THEN E5=E6 3470 E6=(Y-F2)+Z : IF (E6>E7) 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 (Y2<D4) THEN Y2=Y2-D4 : '...= Y*Y mod 4D 3660 IF (Y<D) THEN 3600 : ' else 0 < Z < D & Z2 = Z^2 mod 4D is maximal. 3670 X8=D4-Z2 : Q=(X8+Z*Z)/D4 : X8=X8/O8 : IF NOT (Q=INT(Q)) THEN 3700 3680 X=Z1*Z : X=X-INT(X/B)*B : IF (X=O1) THEN 3800 : ' with 1 = Z*Z1 mod B 3690 Z1=Z1-O1 : IF (Z1>O) 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-B<Z2-B OR X-Z2>W-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 (E6<E5) THEN E5=E6 3780 E6=Y2-X2 : IF (E6>E7) 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*D<F9) THEN 3810 : ' ... until D = B^(P-1) . 3820 IF NOT (D*B-D=W-D) THEN 3700 3830 Z2=D : I=0 : ' Count how many tests of SQRT(D*X)=Y yield results. 3840 Y=D+(O1+Z)*F2 : X=D+Z+Q : GOSUB 3750 3850 Y=D+(O1-Z)*F2+D : X=D-Z+D : X=X+Q+X : GOSUB 3750 3860 GOSUB 3720 : IF NOT (D-Z2=W-Z2) THEN 3700 3870 Y=(D-Z2)+(Z2+(O1-Z)*F2) : X=(D-Z2)+(Z2-Z+Q) : GOSUB 3750 3880 Y=(O1+Z)*F2 : X=Q : GOSUB 3750 3890 IF (I=0) THEN 3700 3900 IF (E5<0 OR E7>0) THEN 3920 3910 R4=O1 : PRINT Q$;E$;B$ : GOTO 3960 3920 IF (E7+U2>U2-F2 OR E5>F2 OR E5+B<F2) THEN 3940 3930 R4=O : PRINT Q$;E$;C$;"." : GOTO 3960 3940 PRINT Q$;H$;C$;" nor ";B$ : PRINT "Observed errors run from ";E5-F2;" to ";F2+E7;" ulps." : IF (E7-E5<B*B) THEN 3960 3950 J1=J1+1 : PRINT S$;"DEFECT: SQR";I$ 3960 L=90 : GOSUB 110 : ' ---- PAUSE ---- =================================== 3970 PRINT "Testing powers Z^i for small integers Z and i :" : GOTO 4120 3980 ' ___ Subroutine to compare Z^I with X = Z*Z*...*Z ( I times ) ___ 3990 Y=Z^I : Q=I : GOSUB 4040 : ' ... test whether Y=X 4000 I=I+1 : IF (I>M) THEN RETURN : ' ... with X = Z^M 4010 X=Z*X : IF (X<W) THEN 3990 4020 RETURN : ' ___ End of comparison subroutine ___ 4030 Y=Z^Q : ' ___ Subroutine to test if Y = X ___ 4040 IF (Y=X) THEN 4080 4050 IF (N>0) 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 (Z<O8*O3) THEN 4230 4260 IF (N>0) 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 (H1<O2) THEN H1=O2 4420 H=O1/H1 : ' ... 1/H1 = H = min{ 1/B, 1/2 } 4430 C1=O1/C :E0=C : Z=E0*H : ' ... C = 1/B^(big integer) << 1 << C1 = 1/C 4440 Y=E0 : E0=Z : Z=E0*H : IF (E0>Z 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<>Y2) THEN U0=Y1 4520 Z0=T0*H : IF (T0>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 Z0<T0 or Z0<Z0+Z0 ... 4590 PRINT : Z=Z0 : Z$="Z0" : IF (Z0>O) 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)<B*U2) THEN 4750 4670 IF (Q9<O1 OR Q9>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)<U2 AND ABS(V9-O2)<B*U2) THEN 4750 4740 N=1 : J1=J1+1 : PRINT "This is a VERY SERIOUS DEFECT." : PRINT : GOTO 4760 4750 PRINT " This is O.K. provided Over/Underflow has NOT just been signaled." 4760 V9=Z*O1 : X9=V9 : V9=O1*Z : Y9=V9 : V9=Z/O1 : IF (Z=X9 AND Z=Y9 AND Z=V9) THEN 4840 4770 N=1 : J2=J2+1 4780 PRINT "DEFECT: What prints as ";Z$;" =";Z;" compares different from" 4790 IF NOT (Z=X9) THEN PRINT " ";Z$;"*1 = ";X9 4800 IF NOT (Z=Y9 OR Y9=X9) THEN PRINT " 1*";Z$;" = ";Y9 4810 IF NOT (Z=V9) THEN PRINT " ";Z$;"/1 = ";V9 4820 IF (Y9=X9) THEN 4840 4830 J2=J2+1 : PRINT "DEFECT:";M$;" does not commute; comparison alleges that" : PRINT " 1*";Z$;" =";Y9;" differs from ";Z$;"*1 =";X9 4840 IF (N>0) THEN GOSUB 110 : ' ---- PAUSE ---- 4850 RETURN : ' end of test for Partial Over/Underflow 4860 L=120 : ' ============================================================== 4870 IF (C1*Y<=C1*Y1) THEN 4890 : ' ... as happens on most machines. 4880 S1=H*S1 : E0=T0 : ' = least positive no. on HP 3000 4890 IF (E1=0 OR E1=E0) THEN 4930 4900 IF (E1<E0) THEN 4920 4910 J2=J2+1 : PRINT "DEFECT: Differences underflow at a higher threshold than Products." : GOTO 4930 4920 J2=J2+1 : PRINT "DEFECT: Products underflow at a higher threshold than Differences." : IF (Z0=O) THEN E0=E1 : ' ... but not if pseudo-zeros exist. 4930 PRINT "Smallest strictly positive number found is E0 ="; E0 4940 Z=E0 : Z$="E0" : GOSUB 4640 : T0=E0 : IF (N=1) THEN T0=Y : ' for CDC 7600 4950 I=4 : IF (E1=O) THEN I=3 : ' ... I=1 if E1=0=U0 , I=2 if E1>0=U0 , 4960 IF (U0=O) THEN I=I-2 : ' ... I=3 if E1=0<U0 , I=4 if E1>0 & 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<>O) THEN 5080 5050 J3=J3+1 : PRINT "FLAW: X =";X;" is Unequal to Z =";Z;" ," : PRINT " yet X-Z yields "; : Z9=X-Z : PRINT Z9;". Should this NOT signal Underflow," 5060 PRINT "this is a SERIOUS DEFECT that causes confusion when innocent statements like" : PRINT " if (X=Z) then ... else ... ( f(X)-f(Z) )/(X-Z) ..." 5070 PRINT "encounter Division by Zero although actually X/Z = 1 + "; (X/Z-F2)-F2 : PRINT 5080 GOTO 5160 : ' ... end of test for X-Z = 0 & X <> 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 5393 ' JTC: reversed inequality of test above, to capture all intended tests 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) THEN 5490 5480 Z=A : GOTO 5470 5490 GOSUB 4280 : ' ... print count of discrepancies. 5500 L=160 : GOSUB 110 : ' ---- PAUSE ---- =================================== 5510 PRINT "Searching for Overflow threshold:" 5520 Y=-C1 : V9=H1*Y 5530 V=Y : Y=V9 : V9=H1*Y : IF (V9<Y) THEN 5530 5540 Z=V9 : PRINT "Can ` Z = -Y ' overflow? Trying it on Y =";Y; : V9=-Y : V0=V9 : IF (V-Y=V+V0) THEN 5560 5550 J3=J3+1 : PRINT " finds a" : PRINT "FLAW: -(-Y) differs from Y" : GOTO 5570 5560 PRINT " seems O.K." 5570 IF (Z=Y) THEN 5590 5580 J1=J1+1 : PRINT S$;"DEFECT: Overflow past ";Y;" shrinks to ";Z 5590 Y=V*(H1*U2-H1) : Z=Y+((O1-H1)*U2)*V : IF (Z<V0) THEN Y=Z 5600 IF (Y<V0) THEN V=Y 5610 IF(V0-V<V0) THEN V=V0 5620 PRINT "Overflow threshold is V = ";V 5630 PRINT "Overflow saturates at V0 = ";V0 5640 PRINT "No overflow should be signaled for V*1 = "; : V9=V*O1 : PRINT V9 : PRINT " nor for V/1 = "; : V9=V/O1 : PRINT V9 : PRINT "Any overflow signal separating this * from one above or below is a DEFECT." 5650 L=170 : ' =============================================================== 5660 IF (-V<V AND -V0<V0 AND -U0<V AND U0<V) THEN 5680 5670 J0=J0+1 : PRINT F$;" Comparisons are confused by Overflow." 5680 L=175 : '================================================================ 5690 PRINT : I=0 : Z=U0 5700 I=I+1 : IF (Z=O) THEN 5770 5710 V9=SQR(Z) : Y=V9*V9 : IF NOT (Y/(O1-B*E9)<Z OR Y>(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<W) THEN 5880 5870 Z$="" : J2=1+J2 : GOTO 5890 5880 Z$=S$ : J1=1+J1 5890 I=1 : GOSUB 5740 5900 IF (I=1) THEN 5920 5910 I=1 : Z=V0 : GOTO 5850 5920 PRINT " * * * * * * * * * *" 5930 L=190 : GOSUB 110 : '---- PAUSE ---- ==================================== 5940 X=U0*V : Y=B*B : IF (X*Y>= 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+R4<O4) THEN 6260 6220 IF (S<O1 OR (B-O2)*(B-O9-O1)<>O) THEN 6250 6230 Z$="854" : IF (B=O2 AND (P-O4*O3*O2)*(P-T7-T7+O1)=O) THEN Z$="754" 6240 PRINT "Rounding appears to conform to the proposed IEEE standard p";Z$ : IF (I3=0) THEN PRINT "except possibly for Double Rounding during Gradual Underflow." 6250 PRINT T$;"appears to be Excellent!" : GOTO 6310 ' *** FIX : go to 4550 6260 PRINT T$;"seems Satisfactory." : GOTO 6310 6270 IF (J0+J1+J2=0 AND J3>0) 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 '------------------------------------------------------------------