|
|
1.1 ! root 1: #undef V9 ! 2: #define NOPAUSE ! 3: /* A C version of Kahan's Floating Point Test "Paranoia" ! 4: ! 5: Thos Sumner, UCSF, Feb. 1985 ! 6: David Gay, BTL, Jan. 1986 ! 7: ! 8: This is a rewrite from the Pascal version by ! 9: ! 10: B. A. Wichmann, 18 Jan. 1985 ! 11: ! 12: (and does NOT exhibit good C programming style). ! 13: ! 14: (C) Apr 19 1983 in BASIC version by: ! 15: Professor W. M. Kahan, ! 16: 567 Evans Hall ! 17: Electrical Engineering & Computer Science Dept. ! 18: University of California ! 19: Berkeley, California 94720 ! 20: USA ! 21: ! 22: converted to Pascal by: ! 23: B. A. Wichmann ! 24: National Physical Laboratory ! 25: Teddington Middx ! 26: TW11 OLW ! 27: UK ! 28: ! 29: converted to C by: ! 30: ! 31: David M. Gay and Thos Sumner ! 32: AT&T Bell Labs Computer Center, Rm. U-76 ! 33: 600 Mountain Avenue University of California ! 34: Murray Hill, NJ 07974 San Francisco, CA 94143 ! 35: USA USA ! 36: ! 37: with simultaneous corrections to the Pascal source (reflected ! 38: in the Pascal source available over netlib). ! 39: [A couple of bug fixes from dgh = sun!dhough incorporated 31 July 1986.] ! 40: ! 41: Reports of results on various systems from all the versions ! 42: of Paranoia are being collected by Richard Karpinski at the ! 43: same address as Thos Sumner. This includes sample outputs, ! 44: bug reports, and criticisms. ! 45: ! 46: You may copy this program freely if you acknowledge its source. ! 47: Comments on the Pascal version to NPL, please. ! 48: ! 49: ! 50: The C version catches signals from floating-point exceptions. ! 51: If signal(SIGFPE,...) is unavailable in your environment, you may ! 52: #define NOSIGNAL to comment out the invocations of signal. ! 53: ! 54: This source file is too big for some C compilers, but may be split ! 55: into pieces. Comments containing "SPLIT" suggest convenient places ! 56: for this splitting. At the end of these comments is an "ed script" ! 57: (for the UNIX(tm) editor ed) that will do this splitting. ! 58: ! 59: By #defining Single when you compile this source, you may obtain ! 60: a single-precision C version of Paranoia. ! 61: ! 62: ! 63: The following is from the introductory commentary from Wichmann's work: ! 64: ! 65: The BASIC program of Kahan is written in Microsoft BASIC using many ! 66: facilities which have no exact analogy in Pascal. The Pascal ! 67: version below cannot therefore be exactly the same. Rather than be ! 68: a minimal transcription of the BASIC program, the Pascal coding ! 69: follows the conventional style of block-structured languages. Hence ! 70: the Pascal version could be useful in producing versions in other ! 71: structured languages. ! 72: ! 73: Rather than use identifiers of minimal length (which therefore have ! 74: little mnemonic significance), the Pascal version uses meaningful ! 75: identifiers as follows [Note: A few changes have been made for C]: ! 76: ! 77: ! 78: BASIC C BASIC C BASIC C ! 79: ! 80: A J S StickyBit ! 81: A1 AInverse J0 NoErrors T ! 82: B Radix [Failure] T0 Underflow ! 83: B1 BInverse J1 NoErrors T2 ThirtyTwo ! 84: B2 RadixD2 [SeriousDefect] T5 OneAndHalf ! 85: B9 BMinusU2 J2 NoErrors T7 TwentySeven ! 86: C [Defect] T8 TwoForty ! 87: C1 CInverse J3 NoErrors U OneUlp ! 88: D [Flaw] U0 UnderflowThreshold ! 89: D4 FourD K PageNo U1 ! 90: E0 L Milestone U2 ! 91: E1 M V ! 92: E2 Exp2 N V0 ! 93: E3 N1 V8 ! 94: E5 MinSqEr O Zero V9 ! 95: E6 SqEr O1 One W ! 96: E7 MaxSqEr O2 Two X ! 97: E8 O3 Three X1 ! 98: E9 O4 Four X8 ! 99: F1 MinusOne O5 Five X9 Random1 ! 100: F2 Half O8 Eight Y ! 101: F3 Third O9 Nine Y1 ! 102: F6 P Precision Y2 ! 103: F9 Q Y9 Random2 ! 104: G1 GMult Q8 Z ! 105: G2 GDiv Q9 Z0 PseudoZero ! 106: G3 GAddSub R Z1 ! 107: H R1 RMult Z2 ! 108: H1 HInverse R2 RDiv Z9 ! 109: I R3 RAddSub ! 110: IO NoTrials R4 RSqrt ! 111: I3 IEEE R9 Random9 ! 112: ! 113: SqRWrng ! 114: ! 115: All the variables in BASIC are true variables and in consequence, ! 116: the program is more difficult to follow since the "constants" must ! 117: be determined (the glossary is very helpful). The Pascal version ! 118: uses Real constants, but checks are added to ensure that the values ! 119: are correctly converted by the compiler. ! 120: ! 121: The major textual change to the Pascal version apart from the ! 122: identifiersis that named procedures are used, inserting parameters ! 123: wherehelpful. New procedures are also introduced. The ! 124: correspondence is as follows: ! 125: ! 126: ! 127: BASIC Pascal ! 128: lines ! 129: ! 130: 90- 140 Pause ! 131: 170- 250 Instructions ! 132: 380- 460 Heading ! 133: 480- 670 Characteristics ! 134: 690- 870 History ! 135: 2940-2950 Random ! 136: 3710-3740 NewD ! 137: 4040-4080 DoesYequalX ! 138: 4090-4110 PrintIfNPositive ! 139: 4640-4850 TestPartialUnderflow ! 140: ! 141: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= ! 142: ! 143: Below is an "ed script" that splits para.c into 10 files ! 144: of the form part[1-8].c, subs.c, and msgs.c, plus a header ! 145: file, paranoia.h, that these files require. ! 146: ! 147: r paranoia.c ! 148: $ ! 149: ?SPLIT ! 150: +,$w msgs.c ! 151: .,$d ! 152: ?SPLIT ! 153: .d ! 154: +d ! 155: -,$w subs.c ! 156: -,$d ! 157: ?part8 ! 158: +d ! 159: ?include ! 160: .,$w part8.c ! 161: .,$d ! 162: -d ! 163: ?part7 ! 164: +d ! 165: ?include ! 166: .,$w part7.c ! 167: .,$d ! 168: -d ! 169: ?part6 ! 170: +d ! 171: ?include ! 172: .,$w part6.c ! 173: .,$d ! 174: -d ! 175: ?part5 ! 176: +d ! 177: ?include ! 178: .,$w part5.c ! 179: .,$d ! 180: -d ! 181: ?part4 ! 182: +d ! 183: ?include ! 184: .,$w part4.c ! 185: .,$d ! 186: -d ! 187: ?part3 ! 188: +d ! 189: ?include ! 190: .,$w part3.c ! 191: .,$d ! 192: -d ! 193: ?part2 ! 194: +d ! 195: ?include ! 196: .,$w part2.c ! 197: .,$d ! 198: ?SPLIT ! 199: .d ! 200: 1,/^#include/-1d ! 201: 1,$w part1.c ! 202: /Computed constants/,$d ! 203: 1,$s/^int/extern &/ ! 204: 1,$s/^FLOAT/extern &/ ! 205: 1,$s/^char/extern &/ ! 206: 1,$s! = .*!;! ! 207: /^Guard/,/^Round/s/^/extern / ! 208: /^jmp_buf/s/^/extern / ! 209: /^Sig_type/s/^/extern / ! 210: s/$/\ ! 211: extern void sigfpe();/ ! 212: w paranoia.h ! 213: q ! 214: ! 215: */ ! 216: ! 217: #include <stdio.h> ! 218: #ifndef NOSIGNAL ! 219: #include <signal.h> ! 220: #endif ! 221: #include <setjmp.h> ! 222: ! 223: extern double fabs(), floor(), log(), pow(), sqrt(); ! 224: ! 225: #ifdef Single ! 226: #define FLOAT float ! 227: #define FABS(x) (float)fabs((double)(x)) ! 228: #define FLOOR(x) (float)floor((double)(x)) ! 229: #define LOG(x) (float)log((double)(x)) ! 230: #define POW(x,y) (float)pow((double)(x),(double)(y)) ! 231: #define SQRT(x) (float)sqrt((double)(x)) ! 232: #else ! 233: #define FLOAT double ! 234: #define FABS(x) fabs(x) ! 235: #define FLOOR(x) floor(x) ! 236: #define LOG(x) log(x) ! 237: #define POW(x,y) pow(x,y) ! 238: #define SQRT(x) sqrt(x) ! 239: #endif ! 240: ! 241: jmp_buf ovfl_buf; ! 242: typedef void (*Sig_type)(); ! 243: Sig_type sigsave; ! 244: ! 245: #define KEYBOARD 0 ! 246: ! 247: FLOAT Radix, BInvrse, RadixD2, BMinusU2; ! 248: FLOAT Sign(), Random(); ! 249: ! 250: /*Small floating point constants.*/ ! 251: FLOAT Zero = 0.0; ! 252: FLOAT Half = 0.5; ! 253: FLOAT One = 1.0; ! 254: FLOAT Two = 2.0; ! 255: FLOAT Three = 3.0; ! 256: FLOAT Four = 4.0; ! 257: FLOAT Five = 5.0; ! 258: FLOAT Eight = 8.0; ! 259: FLOAT Nine = 9.0; ! 260: FLOAT TwentySeven = 27.0; ! 261: FLOAT ThirtyTwo = 32.0; ! 262: FLOAT TwoForty = 240.0; ! 263: FLOAT MinusOne = -1.0; ! 264: FLOAT OneAndHalf = 1.5; ! 265: /*Integer constants*/ ! 266: int NoTrials = 20; /*Number of tests for commutativity. */ ! 267: #define False 0 ! 268: #define True 1 ! 269: ! 270: /* Definitions for declared types ! 271: Guard == (Yes, No); ! 272: Rounding == (Chopped, Rounded, Other); ! 273: Message == packed array [1..40] of char; ! 274: Class == (Flaw, Defect, Serious, Failure); ! 275: */ ! 276: #define Yes 1 ! 277: #define No 0 ! 278: #define Chopped 2 ! 279: #define Rounded 1 ! 280: #define Other 0 ! 281: #define Flaw 3 ! 282: #define Defect 2 ! 283: #define Serious 1 ! 284: #define Failure 0 ! 285: typedef int Guard, Rounding, Class; ! 286: typedef char Message; ! 287: ! 288: /* Declarations of Variables */ ! 289: int Indx; ! 290: char ch[8]; ! 291: FLOAT AInvrse, A1; ! 292: FLOAT C, CInvrse; ! 293: FLOAT D, FourD; ! 294: FLOAT E0, E1, Exp2, E3, MinSqEr; ! 295: FLOAT SqEr, MaxSqEr, E9; ! 296: FLOAT Third; ! 297: FLOAT F6, F9; ! 298: FLOAT H, HInvrse; ! 299: int I; ! 300: FLOAT StickyBit, J; ! 301: FLOAT MyZero; ! 302: FLOAT Precision; ! 303: FLOAT Q, Q9; ! 304: FLOAT R, Random9; ! 305: FLOAT T, Underflow, S; ! 306: FLOAT OneUlp, UfThold, U1, U2; ! 307: FLOAT V, V0, V9; ! 308: FLOAT W; ! 309: FLOAT X, X1, X2, X8, Random1; ! 310: FLOAT Y, Y1, Y2, Random2; ! 311: FLOAT Z, PseudoZero, Z1, Z2, Z9; ! 312: int ErrCnt[4]; ! 313: int fpecount; ! 314: int Milestone; ! 315: int PageNo; ! 316: int M, N, N1; ! 317: Guard GMult, GDiv, GAddSub; ! 318: Rounding RMult, RDiv, RAddSub, RSqrt; ! 319: int Break, Done, NotMonot, Monot, Anomaly, IEEE, ! 320: SqRWrng, UfNGrad; ! 321: /* Computed constants. */ ! 322: /*U1 gap below 1.0, i.e, 1.0-U1 is next number below 1.0 */ ! 323: /*U2 gap above 1.0, i.e, 1.0+U2 is next number above 1.0 */ ! 324: ! 325: /* floating point exception receiver */ ! 326: void ! 327: sigfpe(i) ! 328: { ! 329: fpecount++; ! 330: printf("\n* * * FLOATING-POINT ERROR * * *\n"); ! 331: fflush(stdout); ! 332: if (sigsave) { ! 333: #ifndef NOSIGNAL ! 334: signal(SIGFPE, sigsave); ! 335: #endif ! 336: sigsave = 0; ! 337: longjmp(ovfl_buf, 1); ! 338: } ! 339: abort(); ! 340: } ! 341: ! 342: main() ! 343: { ! 344: #ifdef mc ! 345: char *out; ! 346: ieee_flags("set", "precision", "double", &out); ! 347: #endif ! 348: /* First two assignments use integer right-hand sides. */ ! 349: Zero = 0; ! 350: One = 1; ! 351: Two = One + One; ! 352: Three = Two + One; ! 353: Four = Three + One; ! 354: Five = Four + One; ! 355: Eight = Four + Four; ! 356: Nine = Three * Three; ! 357: TwentySeven = Nine * Three; ! 358: ThirtyTwo = Four * Eight; ! 359: TwoForty = Four * Five * Three * Four; ! 360: MinusOne = -One; ! 361: Half = One / Two; ! 362: OneAndHalf = One + Half; ! 363: ErrCnt[Failure] = 0; ! 364: ErrCnt[Serious] = 0; ! 365: ErrCnt[Defect] = 0; ! 366: ErrCnt[Flaw] = 0; ! 367: PageNo = 1; ! 368: /*=============================================*/ ! 369: Milestone = 0; ! 370: /*=============================================*/ ! 371: #ifndef NOSIGNAL ! 372: signal(SIGFPE, sigfpe); ! 373: #endif ! 374: Instructions(); ! 375: Pause(); ! 376: Heading(); ! 377: Pause(); ! 378: Characteristics(); ! 379: Pause(); ! 380: History(); ! 381: Pause(); ! 382: /*=============================================*/ ! 383: Milestone = 7; ! 384: /*=============================================*/ ! 385: printf("Program is now RUNNING tests on small integers:\n"); ! 386: ! 387: TstCond (Failure, (Zero + Zero == Zero) && (One - One == Zero) ! 388: && (One > Zero) && (One + One == Two), ! 389: "0+0 != 0, 1-1 != 0, 1 <= 0, or 1+1 != 2"); ! 390: Z = - Zero; ! 391: if (Z != 0.0) { ! 392: ErrCnt[Failure] = ErrCnt[Failure] + 1; ! 393: printf("Comparison alleges that -0.0 is Non-zero!\n"); ! 394: U1 = 0.001; ! 395: Radix = 1; ! 396: TstPtUf(); ! 397: } ! 398: TstCond (Failure, (Three == Two + One) && (Four == Three + One) ! 399: && (Four + Two * (- Two) == Zero) ! 400: && (Four - Three - One == Zero), ! 401: "3 != 2+1, 4 != 3+1, 4+2*(-2) != 0, or 4-3-1 != 0"); ! 402: TstCond (Failure, (MinusOne == (0 - One)) ! 403: && (MinusOne + One == Zero ) && (One + MinusOne == Zero) ! 404: && (MinusOne + FABS(One) == Zero) ! 405: && (MinusOne + MinusOne * MinusOne == Zero), ! 406: "-1+1 != 0, (-1)+abs(1) != 0, or -1+(-1)*(-1) != 0"); ! 407: TstCond (Failure, Half + MinusOne + Half == Zero, ! 408: "1/2 + (-1) + 1/2 != 0"); ! 409: /*=============================================*/ ! 410: /*SPLIT ! 411: part2(); ! 412: part3(); ! 413: part4(); ! 414: part5(); ! 415: part6(); ! 416: part7(); ! 417: part8(); ! 418: } ! 419: #include "paranoia.h" ! 420: part2(){ ! 421: */ ! 422: Milestone = 10; ! 423: /*=============================================*/ ! 424: TstCond (Failure, (Nine == Three * Three) ! 425: && (TwentySeven == Nine * Three) && (Eight == Four + Four) ! 426: && (ThirtyTwo == Eight * Four) ! 427: && (ThirtyTwo - TwentySeven - Four - One == Zero), ! 428: "9 != 3*3, 27 != 9*3, 32 != 8*4, or 32-27-4-1 != 0"); ! 429: TstCond (Failure, (Five == Four + One) && ! 430: (TwoForty == Four * Five * Three * Four) ! 431: && (TwoForty / Three - Four * Four * Five == Zero) ! 432: && ( TwoForty / Four - Five * Three * Four == Zero) ! 433: && ( TwoForty / Five - Four * Three * Four == Zero), ! 434: "5 != 4+1, 240/3 != 80, 240/4 != 60, or 240/5 != 48"); ! 435: if (ErrCnt[Failure] == 0) { ! 436: printf("-1, 0, 1/2, 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K.\n"); ! 437: printf("\n"); ! 438: } ! 439: printf("Searching for Radix and Precision.\n"); ! 440: W = One; ! 441: do { ! 442: W = W + W; ! 443: Y = W + One; ! 444: Z = Y - W; ! 445: Y = Z - One; ! 446: } while (MinusOne + FABS(Y) < Zero); ! 447: /*.. now W is just big enough that |((W+1)-W)-1| >= 1 ...*/ ! 448: Precision = Zero; ! 449: Y = One; ! 450: do { ! 451: Radix = W + Y; ! 452: Y = Y + Y; ! 453: Radix = Radix - W; ! 454: } while ( Radix == Zero); ! 455: if (Radix < Two) Radix = One; ! 456: printf("Radix = %f .\n", Radix); ! 457: if (Radix != 1) { ! 458: W = One; ! 459: do { ! 460: Precision = Precision + One; ! 461: W = W * Radix; ! 462: Y = W + One; ! 463: } while ((Y - W) == One); ! 464: } ! 465: /*... now W == Radix^Precision is barely too big to satisfy (W+1)-W == 1 ! 466: ...*/ ! 467: U1 = One / W; ! 468: U2 = Radix * U1; ! 469: printf("Closest relative separation found is U1 = %.7e .\n\n", U1); ! 470: printf("Recalculating radix and precision\n "); ! 471: ! 472: /*save old values*/ ! 473: E0 = Radix; ! 474: E1 = U1; ! 475: E9 = U2; ! 476: E3 = Precision; ! 477: ! 478: X = Four / Three; ! 479: Third = X - One; ! 480: F6 = Half - Third; ! 481: X = F6 + F6; ! 482: X = FABS(X - Third); ! 483: if (X < U2) X = U2; ! 484: ! 485: /*... now X = (unknown no.) ulps of 1+...*/ ! 486: do { ! 487: U2 = X; ! 488: Y = Half * U2 + ThirtyTwo * U2 * U2; ! 489: Y = One + Y; ! 490: X = Y - One; ! 491: } while ( ! ((U2 <= X) || (X <= Zero))); ! 492: ! 493: /*... now U2 == 1 ulp of 1 + ... */ ! 494: X = Two / Three; ! 495: F6 = X - Half; ! 496: Third = F6 + F6; ! 497: X = Third - Half; ! 498: X = FABS(X + F6); ! 499: if (X < U1) X = U1; ! 500: ! 501: /*... now X == (unknown no.) ulps of 1 -... */ ! 502: do { ! 503: U1 = X; ! 504: Y = Half * U1 + ThirtyTwo * U1 * U1; ! 505: Y = Half - Y; ! 506: X = Half + Y; ! 507: Y = Half - X; ! 508: X = Half + Y; ! 509: } while ( ! ((U1 <= X) || (X <= Zero))); ! 510: /*... now U1 == 1 ulp of 1 - ... */ ! 511: if (U1 == E1) printf("confirms closest relative separation U1 .\n"); ! 512: else printf("gets better closest relative separation U1 = %.7e .\n", U1); ! 513: W = One / U1; ! 514: F9 = (Half - U1) + Half; ! 515: Radix = FLOOR(0.01 + U2 / U1); ! 516: if (Radix == E0) printf("Radix confirmed.\n"); ! 517: else printf("MYSTERY: recalculated Radix = %.7e .\n", Radix); ! 518: TstCond (Defect, Radix <= Eight + Eight, ! 519: "Radix is too big: roundoff problems"); ! 520: TstCond (Flaw, (Radix == Two) || (Radix == 10) ! 521: || (Radix == One), "Radix is not as good as 2 or 10"); ! 522: /*=============================================*/ ! 523: Milestone = 20; ! 524: /*=============================================*/ ! 525: TstCond (Failure, F9 - Half < Half, ! 526: "(1-U1)-1/2 < 1/2 is FALSE, prog. fails?"); ! 527: X = F9; ! 528: I = 1; ! 529: Y = X - Half; ! 530: Z = Y - Half; ! 531: TstCond (Failure, (X != One) ! 532: || (Z == Zero), "Comparison is fuzzy,X=1 but X-1/2-1/2 != 0"); ! 533: X = One + U2; ! 534: I = 0; ! 535: /*=============================================*/ ! 536: Milestone = 25; ! 537: /*=============================================*/ ! 538: /*... BMinusU2 = nextafter(Radix, 0) */ ! 539: BMinusU2 = Radix - One; ! 540: BMinusU2 = (BMinusU2 - U2) + One; ! 541: /* Purify Integers */ ! 542: if (Radix != One) { ! 543: X = - TwoForty * LOG(U1) / LOG(Radix); ! 544: Y = FLOOR(Half + X); ! 545: if (FABS(X - Y) * Four < One) X = Y; ! 546: Precision = X / TwoForty; ! 547: Y = FLOOR(Half + Precision); ! 548: if (FABS(Precision - Y) * TwoForty < Half) Precision = Y; ! 549: } ! 550: if ((Precision != FLOOR(Precision)) || (Radix == One)) { ! 551: printf("Precision cannot be characterized by an Integer number\n"); ! 552: printf("of significant digits but, by itself, this is a minor flaw.\n"); ! 553: } ! 554: if (Radix == One) ! 555: printf("logarithmic encoding has precision characterized solely by U1.\n"); ! 556: else printf("The number of significant digits of the Radix is %f .\n", ! 557: Precision); ! 558: TstCond (Serious, U2 * Nine * Nine * TwoForty < One, ! 559: "Precision worse than 5 decimal figures "); ! 560: /*=============================================*/ ! 561: Milestone = 30; ! 562: /*=============================================*/ ! 563: /* Test for extra-precise subepressions */ ! 564: X = FABS(((Four / Three - One) - One / Four) * Three - One / Four); ! 565: do { ! 566: Z2 = X; ! 567: X = (One + (Half * Z2 + ThirtyTwo * Z2 * Z2)) - One; ! 568: } while ( ! ((Z2 <= X) || (X <= Zero))); ! 569: X = Y = Z = FABS((Three / Four - Two / Three) * Three - One / Four); ! 570: do { ! 571: Z1 = Z; ! 572: Z = (One / Two - ((One / Two - (Half * Z1 + ThirtyTwo * Z1 * Z1)) ! 573: + One / Two)) + One / Two; ! 574: } while ( ! ((Z1 <= Z) || (Z <= Zero))); ! 575: do { ! 576: do { ! 577: Y1 = Y; ! 578: Y = (Half - ((Half - (Half * Y1 + ThirtyTwo * Y1 * Y1)) + Half ! 579: )) + Half; ! 580: } while ( ! ((Y1 <= Y) || (Y <= Zero))); ! 581: X1 = X; ! 582: X = ((Half * X1 + ThirtyTwo * X1 * X1) - F9) + F9; ! 583: } while ( ! ((X1 <= X) || (X <= Zero))); ! 584: if ((X1 != Y1) || (X1 != Z1)) { ! 585: BadCond(Serious, "Disagreements among the values X1, Y1, Z1,\n"); ! 586: printf("respectively %.7e, %.7e, %.7e,\n", X1, Y1, Z1); ! 587: printf("are symptoms of inconsistencies introduced\n"); ! 588: printf("by extra-precise evaluation of arithmetic subexpressions.\n"); ! 589: notify("Possibly some part of this"); ! 590: if ((X1 == U1) || (Y1 == U1) || (Z1 == U1)) printf( ! 591: "That feature is not tested further by this program.\n") ; ! 592: } ! 593: else { ! 594: if ((Z1 != U1) || (Z2 != U2)) { ! 595: if ((Z1 >= U1) || (Z2 >= U2)) { ! 596: BadCond(Failure, ""); ! 597: notify("Precision"); ! 598: printf("\tU1 = %.7e, Z1 - U1 = %.7e\n",U1,Z1-U1); ! 599: printf("\tU2 = %.7e, Z2 - U2 = %.7e\n",U2,Z2-U2); ! 600: } ! 601: else { ! 602: if ((Z1 <= Zero) || (Z2 <= Zero)) { ! 603: printf("Because of unusual Radix = %f", Radix); ! 604: printf(", or exact rational arithmetic a result\n"); ! 605: printf("Z1 = %.7e, or Z2 = %.7e ", Z1, Z2); ! 606: notify("of an\nextra-precision"); ! 607: } ! 608: if (Z1 != Z2 || Z1 > Zero) { ! 609: X = Z1 / U1; ! 610: Y = Z2 / U2; ! 611: if (Y > X) X = Y; ! 612: Q = - LOG(X); ! 613: printf("Some subexpressions appear to be calculated extra\n"); ! 614: printf("precisely with about %g extra B-digits, i.e.\n", ! 615: (Q / LOG(Radix))); ! 616: printf("roughly %g extra significant decimals.\n", ! 617: Q / LOG(10.)); ! 618: } ! 619: printf("That feature is not tested further by this program.\n"); ! 620: } ! 621: } ! 622: } ! 623: Pause(); ! 624: /*=============================================*/ ! 625: /*SPLIT ! 626: } ! 627: #include "paranoia.h" ! 628: part3(){ ! 629: */ ! 630: Milestone = 35; ! 631: /*=============================================*/ ! 632: if (Radix >= Two) { ! 633: X = W / (Radix * Radix); ! 634: Y = X + One; ! 635: Z = Y - X; ! 636: T = Z + U2; ! 637: X = T - Z; ! 638: TstCond (Failure, X == U2, ! 639: "Subtraction is not normalized X=Y,X+Z != Y+Z!"); ! 640: if (X == U2) printf( ! 641: "Subtraction appears to be normalized, as it should be."); ! 642: } ! 643: printf("\nChecking for guard digit in *, /, and -.\n"); ! 644: Y = F9 * One; ! 645: Z = One * F9; ! 646: X = F9 - Half; ! 647: Y = (Y - Half) - X; ! 648: Z = (Z - Half) - X; ! 649: X = One + U2; ! 650: T = X * Radix; ! 651: R = Radix * X; ! 652: X = T - Radix; ! 653: X = X - Radix * U2; ! 654: T = R - Radix; ! 655: T = T - Radix * U2; ! 656: X = X * (Radix - One); ! 657: T = T * (Radix - One); ! 658: if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)) GMult = Yes; ! 659: else { ! 660: GMult = No; ! 661: TstCond (Serious, False, ! 662: "* lacks a Guard Digit, so 1*X != X"); ! 663: } ! 664: Z = Radix * U2; ! 665: X = One + Z; ! 666: Y = FABS((X + Z) - X * X) - U2; ! 667: X = One - U2; ! 668: Z = FABS((X - U2) - X * X) - U1; ! 669: TstCond (Failure, (Y <= Zero) ! 670: && (Z <= Zero), "* gets too many final digits wrong.\n"); ! 671: Y = One - U2; ! 672: X = One + U2; ! 673: Z = One / Y; ! 674: Y = Z - X; ! 675: X = One / Three; ! 676: Z = Three / Nine; ! 677: X = X - Z; ! 678: T = Nine / TwentySeven; ! 679: Z = Z - T; ! 680: TstCond(Defect, X == Zero && Y == Zero && Z == Zero, ! 681: "Division lacks a Guard Digit, so error can exceed 1 ulp\nor 1/3 and 3/9 and 9/27 may disagree"); ! 682: Y = F9 / One; ! 683: X = F9 - Half; ! 684: Y = (Y - Half) - X; ! 685: X = One + U2; ! 686: T = X / One; ! 687: X = T - X; ! 688: if ((X == Zero) && (Y == Zero) && (Z == Zero)) GDiv = Yes; ! 689: else { ! 690: GDiv = No; ! 691: TstCond (Serious, False, ! 692: "Division lacks a Guard Digit, so X/1 != X"); ! 693: } ! 694: X = One / (One + U2); ! 695: Y = X - Half - Half; ! 696: TstCond (Serious, Y < Zero, ! 697: "Computed value of 1/1.000..1 >= 1"); ! 698: X = One - U2; ! 699: Y = One + Radix * U2; ! 700: Z = X * Radix; ! 701: T = Y * Radix; ! 702: R = Z / Radix; ! 703: StickyBit = T / Radix; ! 704: X = R - X; ! 705: Y = StickyBit - Y; ! 706: TstCond (Failure, X == Zero && Y == Zero, ! 707: "* and/or / gets too many last digits wrong"); ! 708: Y = One - U1; ! 709: X = One - F9; ! 710: Y = One - Y; ! 711: T = Radix - U2; ! 712: Z = Radix - BMinusU2; ! 713: T = Radix - T; ! 714: if ((X == U1) && (Y == U1) && (Z == U2) && (T == U2)) GAddSub = Yes; ! 715: else { ! 716: GAddSub = No; ! 717: TstCond (Serious, False, ! 718: "- lacks Guard Digit, so cancellation is obscured"); ! 719: } ! 720: if (F9 != One && F9 - One >= Zero) { ! 721: BadCond(Serious, "comparison alleges (1-U1) < 1 although\n"); ! 722: printf(" subtraction yields (1-U1) - 1 = 0 , thereby vitiating\n"); ! 723: printf(" such precautions against division by zero as\n"); ! 724: printf(" ... if (X == 1.0) {.....} else {.../(X-1.0)...}\n"); ! 725: } ! 726: if (GMult == Yes && GDiv == Yes && GAddSub == Yes) printf( ! 727: " *, /, and - appear to have guard digits, as they should.\n"); ! 728: /*=============================================*/ ! 729: Milestone = 40; ! 730: /*=============================================*/ ! 731: Pause(); ! 732: printf("Checking rounding on multiply, divide and add/subtract.\n"); ! 733: RMult = Other; ! 734: RDiv = Other; ! 735: RAddSub = Other; ! 736: RadixD2 = Radix / Two; ! 737: A1 = Two; ! 738: Done = False; ! 739: do { ! 740: AInvrse = Radix; ! 741: do { ! 742: X = AInvrse; ! 743: AInvrse = AInvrse / A1; ! 744: } while ( ! (FLOOR(AInvrse) != AInvrse)); ! 745: Done = (X == One) || (A1 > Three); ! 746: if (! Done) A1 = Nine + One; ! 747: } while ( ! (Done)); ! 748: if (X == One) A1 = Radix; ! 749: AInvrse = One / A1; ! 750: X = A1; ! 751: Y = AInvrse; ! 752: Done = False; ! 753: do { ! 754: Z = X * Y - Half; ! 755: TstCond (Failure, Z == Half, ! 756: "X * (1/X) differs from 1"); ! 757: Done = X == Radix; ! 758: X = Radix; ! 759: Y = One / X; ! 760: } while ( ! (Done)); ! 761: Y2 = One + U2; ! 762: Y1 = One - U2; ! 763: X = OneAndHalf - U2; ! 764: Y = OneAndHalf + U2; ! 765: Z = (X - U2) * Y2; ! 766: T = Y * Y1; ! 767: Z = Z - X; ! 768: T = T - X; ! 769: X = X * Y2; ! 770: Y = (Y + U2) * Y1; ! 771: X = X - OneAndHalf; ! 772: Y = Y - OneAndHalf; ! 773: if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T <= Zero)) { ! 774: X = (OneAndHalf + U2) * Y2; ! 775: Y = OneAndHalf - U2 - U2; ! 776: Z = OneAndHalf + U2 + U2; ! 777: T = (OneAndHalf - U2) * Y1; ! 778: X = X - (Z + U2); ! 779: StickyBit = Y * Y1; ! 780: S = Z * Y2; ! 781: T = T - Y; ! 782: Y = (U2 - Y) + StickyBit; ! 783: Z = S - (Z + U2 + U2); ! 784: StickyBit = (Y2 + U2) * Y1; ! 785: Y1 = Y2 * Y1; ! 786: StickyBit = StickyBit - Y2; ! 787: Y1 = Y1 - Half; ! 788: if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero) ! 789: && ( StickyBit == Zero) && (Y1 == Half)) { ! 790: RMult = Rounded; ! 791: printf("Multiplication appears to round correctly.\n"); ! 792: } ! 793: else if ((X + U2 == Zero) && (Y < Zero) && (Z + U2 == Zero) ! 794: && (T < Zero) && (StickyBit + U2 == Zero) ! 795: && (Y1 < Half)) { ! 796: RMult = Chopped; ! 797: printf("Multiplication appears to chop.\n"); ! 798: } ! 799: else printf("* is neither chopped nor correctly rounded.\n"); ! 800: if ((RMult == Rounded) && (GMult == No)) notify("Multiplication"); ! 801: } ! 802: else printf("* is neither chopped nor correctly rounded.\n"); ! 803: /*=============================================*/ ! 804: Milestone = 45; ! 805: /*=============================================*/ ! 806: Y2 = One + U2; ! 807: Y1 = One - U2; ! 808: Z = OneAndHalf + U2 + U2; ! 809: X = Z / Y2; ! 810: T = OneAndHalf - U2 - U2; ! 811: Y = (T - U2) / Y1; ! 812: Z = (Z + U2) / Y2; ! 813: X = X - OneAndHalf; ! 814: Y = Y - T; ! 815: T = T / Y1; ! 816: Z = Z - (OneAndHalf + U2); ! 817: T = (U2 - OneAndHalf) + T; ! 818: if (! ((X > Zero) || (Y > Zero) || (Z > Zero) || (T > Zero))) { ! 819: X = OneAndHalf / Y2; ! 820: Y = OneAndHalf - U2; ! 821: Z = OneAndHalf + U2; ! 822: X = X - Y; ! 823: T = OneAndHalf / Y1; ! 824: Y = Y / Y1; ! 825: T = T - (Z + U2); ! 826: Y = Y - Z; ! 827: Z = Z / Y2; ! 828: Y1 = (Y2 + U2) / Y2; ! 829: Z = Z - OneAndHalf; ! 830: Y2 = Y1 - Y2; ! 831: Y1 = (F9 - U1) / F9; ! 832: if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero) ! 833: && (Y2 == Zero) && (Y2 == Zero) ! 834: && (Y1 - Half == F9 - Half )) { ! 835: RDiv = Rounded; ! 836: printf("Division appears to round correctly.\n"); ! 837: if (GDiv == No) notify("Division"); ! 838: } ! 839: else if ((X < Zero) && (Y < Zero) && (Z < Zero) && (T < Zero) ! 840: && (Y2 < Zero) && (Y1 - Half < F9 - Half)) { ! 841: RDiv = Chopped; ! 842: printf("Division appears to chop.\n"); ! 843: } ! 844: } ! 845: if (RDiv == Other) printf("/ is neither chopped nor correctly rounded.\n"); ! 846: BInvrse = One / Radix; ! 847: TstCond (Failure, (BInvrse * Radix - Half == Half), ! 848: "Radix * ( 1 / Radix ) differs from 1"); ! 849: /*=============================================*/ ! 850: /*SPLIT ! 851: } ! 852: #include "paranoia.h" ! 853: part4(){ ! 854: */ ! 855: Milestone = 50; ! 856: /*=============================================*/ ! 857: TstCond (Failure, ((F9 + U1) - Half == Half) ! 858: && ((BMinusU2 + U2 ) - One == Radix - One), ! 859: "Incomplete carry-propagation in Addition"); ! 860: X = One - U1 * U1; ! 861: Y = One + U2 * (One - U2); ! 862: Z = F9 - Half; ! 863: X = (X - Half) - Z; ! 864: Y = Y - One; ! 865: if ((X == Zero) && (Y == Zero)) { ! 866: RAddSub = Chopped; ! 867: printf("Add/Subtract appears to be chopped.\n"); ! 868: } ! 869: if (GAddSub == Yes) { ! 870: X = (Half + U2) * U2; ! 871: Y = (Half - U2) * U2; ! 872: X = One + X; ! 873: Y = One + Y; ! 874: X = (One + U2) - X; ! 875: Y = One - Y; ! 876: if ((X == Zero) && (Y == Zero)) { ! 877: X = (Half + U2) * U1; ! 878: Y = (Half - U2) * U1; ! 879: X = One - X; ! 880: Y = One - Y; ! 881: X = F9 - X; ! 882: Y = One - Y; ! 883: if ((X == Zero) && (Y == Zero)) { ! 884: RAddSub = Rounded; ! 885: printf("Addition/Subtraction appears to round correctly.\n"); ! 886: if (GAddSub == No) notify("Add/Subtract"); ! 887: } ! 888: else printf("Addition/Subtraction neither rounds nor chops.\n"); ! 889: } ! 890: else printf("Addition/Subtraction neither rounds nor chops.\n"); ! 891: } ! 892: else printf("Addition/Subtraction neither rounds nor chops.\n"); ! 893: S = One; ! 894: X = One + Half * (One + Half); ! 895: Y = (One + U2) * Half; ! 896: Z = X - Y; ! 897: T = Y - X; ! 898: StickyBit = Z + T; ! 899: if (StickyBit != Zero) { ! 900: S = Zero; ! 901: BadCond(Flaw, "(X - Y) + (Y - X) is non zero!\n"); ! 902: } ! 903: StickyBit = Zero; ! 904: if ((GMult == Yes) && (GDiv == Yes) && (GAddSub == Yes) ! 905: && (RMult == Rounded) && (RDiv == Rounded) ! 906: && (RAddSub == Rounded) && (FLOOR(RadixD2) == RadixD2)) { ! 907: printf("Checking for sticky bit.\n"); ! 908: X = (Half + U1) * U2; ! 909: Y = Half * U2; ! 910: Z = One + Y; ! 911: T = One + X; ! 912: if ((Z - One <= Zero) && (T - One >= U2)) { ! 913: Z = T + Y; ! 914: Y = Z - X; ! 915: if ((Z - T >= U2) && (Y - T == Zero)) { ! 916: X = (Half + U1) * U1; ! 917: Y = Half * U1; ! 918: Z = One - Y; ! 919: T = One - X; ! 920: if ((Z - One == Zero) && (T - F9 == Zero)) { ! 921: Z = (Half - U1) * U1; ! 922: T = F9 - Z; ! 923: Q = F9 - Y; ! 924: if ((T - F9 == Zero) && (F9 - U1 - Q == Zero)) { ! 925: Z = (One + U2) * OneAndHalf; ! 926: T = (OneAndHalf + U2) - Z + U2; ! 927: X = One + Half / Radix; ! 928: Y = One + Radix * U2; ! 929: Z = X * Y; ! 930: if (T == Zero && X + Radix * U2 - Z == Zero) { ! 931: if (Radix != Two) { ! 932: X = Two + U2; ! 933: Y = X / Two; ! 934: if ((Y - One == Zero)) StickyBit = S; ! 935: } ! 936: else StickyBit = S; ! 937: } ! 938: } ! 939: } ! 940: } ! 941: } ! 942: } ! 943: if (StickyBit == One) printf("Sticky bit apparently used correctly.\n"); ! 944: else printf("Sticky bit used incorrectly or not at all.\n"); ! 945: TstCond (Flaw, !(GMult == No || GDiv == No || GAddSub == No || ! 946: RMult == Other || RDiv == Other || RAddSub == Other), ! 947: "lack(s) of guard digits or failure(s) to correctly round or chop\n(noted above) count as one flaw in the final tally below"); ! 948: /*=============================================*/ ! 949: Milestone = 60; ! 950: /*=============================================*/ ! 951: printf("\n"); ! 952: printf("Does Multiplication commute? "); ! 953: printf("Testing on %d random pairs.\n", NoTrials); ! 954: Random9 = SQRT(3.0); ! 955: Random1 = Third; ! 956: I = 1; ! 957: do { ! 958: X = Random(); ! 959: Y = Random(); ! 960: Z9 = Y * X; ! 961: Z = X * Y; ! 962: Z9 = Z - Z9; ! 963: I = I + 1; ! 964: } while ( ! ((I > NoTrials) || (Z9 != Zero))); ! 965: if (I == NoTrials) { ! 966: Random1 = One + Half / Three; ! 967: Random2 = (U2 + U1) + One; ! 968: Z = Random1 * Random2; ! 969: Y = Random2 * Random1; ! 970: Z9 = (One + Half / Three) * ((U2 + U1) + One) - (One + Half / ! 971: Three) * ((U2 + U1) + One); ! 972: } ! 973: if (! ((I == NoTrials) || (Z9 == Zero))) ! 974: BadCond(Defect, "X * Y == Y * X trial fails.\n"); ! 975: else printf(" No failures found in %d integer pairs.\n", NoTrials); ! 976: /*=============================================*/ ! 977: Milestone = 70; ! 978: /*=============================================*/ ! 979: printf("\nRunning test of square root(x).\n"); ! 980: TstCond (Failure, (Zero == SQRT(Zero)) ! 981: && (- Zero == SQRT(- Zero)) ! 982: && (One == SQRT(One)), "Square root of 0.0, -0.0 or 1.0 wrong"); ! 983: MinSqEr = Zero; ! 984: MaxSqEr = Zero; ! 985: J = Zero; ! 986: X = Radix; ! 987: OneUlp = U2; ! 988: SqXMinX (Serious); ! 989: X = BInvrse; ! 990: OneUlp = BInvrse * U1; ! 991: SqXMinX (Serious); ! 992: X = U1; ! 993: OneUlp = U1 * U1; ! 994: SqXMinX (Serious); ! 995: if (J != Zero) Pause(); ! 996: printf("Testing if sqrt(X * X) == X for %d Integers X.\n", NoTrials); ! 997: J = Zero; ! 998: X = Two; ! 999: Y = Radix; ! 1000: if ((Radix != One)) do { ! 1001: X = Y; ! 1002: Y = Radix * Y; ! 1003: } while ( ! ((Y - X >= NoTrials))); ! 1004: OneUlp = X * U2; ! 1005: I = 1; ! 1006: while (I <= NoTrials) { ! 1007: X = X + One; ! 1008: SqXMinX (Defect); ! 1009: if (J > Zero) break; ! 1010: I = I + 1; ! 1011: } ! 1012: printf("Test for sqrt monotonicity.\n"); ! 1013: I = - 1; ! 1014: X = BMinusU2; ! 1015: Y = Radix; ! 1016: Z = Radix + Radix * U2; ! 1017: NotMonot = False; ! 1018: Monot = False; ! 1019: while ( ! (NotMonot || Monot)) { ! 1020: I = I + 1; ! 1021: X = SQRT(X); ! 1022: Q = SQRT(Y); ! 1023: Z = SQRT(Z); ! 1024: if ((X > Q) || (Q > Z)) NotMonot = True; ! 1025: else { ! 1026: Q = FLOOR(Q + Half); ! 1027: if ((I > 0) || (Radix == Q * Q)) Monot = True; ! 1028: else if (I > 0) { ! 1029: if (I > 1) Monot = True; ! 1030: else { ! 1031: Y = Y * BInvrse; ! 1032: X = Y - U1; ! 1033: Z = Y + U1; ! 1034: } ! 1035: } ! 1036: else { ! 1037: Y = Q; ! 1038: X = Y - U2; ! 1039: Z = Y + U2; ! 1040: } ! 1041: } ! 1042: } ! 1043: if (Monot) printf("sqrt has passed a test for Monotonicity.\n"); ! 1044: else { ! 1045: BadCond(Defect, ""); ! 1046: printf("sqrt(X) is non-monotonic for X near %.7e .\n", Y); ! 1047: } ! 1048: /*=============================================*/ ! 1049: /*SPLIT ! 1050: } ! 1051: #include "paranoia.h" ! 1052: part5(){ ! 1053: */ ! 1054: Milestone = 80; ! 1055: /*=============================================*/ ! 1056: MinSqEr = MinSqEr + Half; ! 1057: MaxSqEr = MaxSqEr - Half; ! 1058: Y = (SQRT(One + U2) - One) / U2; ! 1059: SqEr = (Y - One) + U2 / Eight; ! 1060: if (SqEr > MaxSqEr) MaxSqEr = SqEr; ! 1061: SqEr = Y + U2 / Eight; ! 1062: if (SqEr < MinSqEr) MinSqEr = SqEr; ! 1063: Y = ((SQRT(F9) - U2) - (One - U2)) / U1; ! 1064: SqEr = Y + U1 / Eight; ! 1065: if (SqEr > MaxSqEr) MaxSqEr = SqEr; ! 1066: SqEr = (Y + One) + U1 / Eight; ! 1067: if (SqEr < MinSqEr) MinSqEr = SqEr; ! 1068: OneUlp = U2; ! 1069: X = OneUlp; ! 1070: for( Indx = 1; Indx <= 3; ++Indx) { ! 1071: Y = SQRT((X + U1 + X) + F9); ! 1072: Y = ((Y - U2) - ((One - U2) + X)) / OneUlp; ! 1073: Z = ((U1 - X) + F9) * Half * X * X / OneUlp; ! 1074: SqEr = (Y + Half) + Z; ! 1075: if (SqEr < MinSqEr) MinSqEr = SqEr; ! 1076: SqEr = (Y - Half) + Z; ! 1077: if (SqEr > MaxSqEr) MaxSqEr = SqEr; ! 1078: if (((Indx == 1) || (Indx == 3))) ! 1079: X = OneUlp * Sign (X) * FLOOR(Eight / (Nine * SQRT(OneUlp))); ! 1080: else { ! 1081: OneUlp = U1; ! 1082: X = - OneUlp; ! 1083: } ! 1084: } ! 1085: /*=============================================*/ ! 1086: Milestone = 85; ! 1087: /*=============================================*/ ! 1088: SqRWrng = False; ! 1089: Anomaly = False; ! 1090: RSqrt = Other; /* ~dgh */ ! 1091: if (Radix != One) { ! 1092: printf("Testing whether sqrt is rounded or chopped.\n"); ! 1093: D = FLOOR(Half + POW(Radix, One + Precision - FLOOR(Precision))); ! 1094: /* ... == Radix^(1 + fract) if (Precision == Integer + fract. */ ! 1095: X = D / Radix; ! 1096: Y = D / A1; ! 1097: if ((X != FLOOR(X)) || (Y != FLOOR(Y))) { ! 1098: Anomaly = True; ! 1099: } ! 1100: else { ! 1101: X = Zero; ! 1102: Z2 = X; ! 1103: Y = One; ! 1104: Y2 = Y; ! 1105: Z1 = Radix - One; ! 1106: FourD = Four * D; ! 1107: do { ! 1108: if (Y2 > Z2) { ! 1109: Q = Radix; ! 1110: Y1 = Y; ! 1111: do { ! 1112: X1 = FABS(Q + FLOOR(Half - Q / Y1) * Y1); ! 1113: Q = Y1; ! 1114: Y1 = X1; ! 1115: } while ( ! (X1 <= Zero)); ! 1116: if (Q <= One) { ! 1117: Z2 = Y2; ! 1118: Z = Y; ! 1119: } ! 1120: } ! 1121: Y = Y + Two; ! 1122: X = X + Eight; ! 1123: Y2 = Y2 + X; ! 1124: if (Y2 >= FourD) Y2 = Y2 - FourD; ! 1125: } while ( ! (Y >= D)); ! 1126: X8 = FourD - Z2; ! 1127: Q = (X8 + Z * Z) / FourD; ! 1128: X8 = X8 / Eight; ! 1129: if (Q != FLOOR(Q)) Anomaly = True; ! 1130: else { ! 1131: Break = False; ! 1132: do { ! 1133: X = Z1 * Z; ! 1134: X = X - FLOOR(X / Radix) * Radix; ! 1135: if (X == One) ! 1136: Break = True; ! 1137: else ! 1138: Z1 = Z1 - One; ! 1139: } while ( ! (Break || (Z1 <= Zero))); ! 1140: if ((Z1 <= Zero) && (! Break)) Anomaly = True; ! 1141: else { ! 1142: if (Z1 > RadixD2) Z1 = Z1 - Radix; ! 1143: do { ! 1144: NewD(); ! 1145: } while ( ! (U2 * D >= F9)); ! 1146: if (D * Radix - D != W - D) Anomaly = True; ! 1147: else { ! 1148: Z2 = D; ! 1149: I = 0; ! 1150: Y = D + (One + Z) * Half; ! 1151: X = D + Z + Q; ! 1152: SR3750(); ! 1153: Y = D + (One - Z) * Half + D; ! 1154: X = D - Z + D; ! 1155: X = X + Q + X; ! 1156: SR3750(); ! 1157: NewD(); ! 1158: if (D - Z2 != W - Z2) Anomaly = True; ! 1159: else { ! 1160: Y = (D - Z2) + (Z2 + (One - Z) * Half); ! 1161: X = (D - Z2) + (Z2 - Z + Q); ! 1162: SR3750(); ! 1163: Y = (One + Z) * Half; ! 1164: X = Q; ! 1165: SR3750(); ! 1166: if (I == 0) Anomaly = True; ! 1167: } ! 1168: } ! 1169: } ! 1170: } ! 1171: } ! 1172: if ((I == 0) || Anomaly) { ! 1173: BadCond(Failure, "Anomalous arithmetic with Integer < "); ! 1174: printf("Radix^Precision = %.7e\n", W); ! 1175: printf(" fails test whether sqrt rounds or chops.\n"); ! 1176: SqRWrng = True; ! 1177: } ! 1178: } ! 1179: if (! Anomaly) { ! 1180: if (! ((MinSqEr < Zero) || (MaxSqEr > Zero))) { ! 1181: RSqrt = Rounded; ! 1182: printf("Square root appears to be correctly rounded.\n"); ! 1183: } ! 1184: else { ! 1185: if ((MaxSqEr + U2 > U2 - Half) || (MinSqEr > Half) ! 1186: || (MinSqEr + Radix < Half)) SqRWrng = True; ! 1187: else { ! 1188: RSqrt = Chopped; ! 1189: printf("Square root appears to be chopped.\n"); ! 1190: } ! 1191: } ! 1192: } ! 1193: if (SqRWrng) { ! 1194: printf("Square root is neither chopped nor correctly rounded.\n"); ! 1195: printf("Observed errors run from %.7e ", MinSqEr - Half); ! 1196: printf("to %.7e ulps.\n", Half + MaxSqEr); ! 1197: TstCond (Serious, MaxSqEr - MinSqEr < Radix * Radix, ! 1198: "sqrt gets too many last digits wrong"); ! 1199: } ! 1200: /*=============================================*/ ! 1201: Milestone = 90; ! 1202: /*=============================================*/ ! 1203: Pause(); ! 1204: printf("Testing powers Z^i for small Integers Z and i.\n"); ! 1205: N = 0; ! 1206: /* ... test powers of zero. */ ! 1207: I = 0; ! 1208: Z = -Zero; ! 1209: M = 3.0; ! 1210: Break = False; ! 1211: do { ! 1212: X = One; ! 1213: SR3980(); ! 1214: if (I <= 10) { ! 1215: I = 1023; ! 1216: SR3980(); ! 1217: } ! 1218: if (Z == MinusOne) Break = True; ! 1219: else { ! 1220: Z = MinusOne; ! 1221: PrintIfNPositive(); ! 1222: N = 0; ! 1223: /* .. if(-1)^N is invalid, replace MinusOne by One. */ ! 1224: I = - 4; ! 1225: } ! 1226: } while ( ! Break); ! 1227: PrintIfNPositive(); ! 1228: N1 = N; ! 1229: N = 0; ! 1230: Z = A1; ! 1231: M = FLOOR(Two * LOG(W) / LOG(A1)); ! 1232: Break = False; ! 1233: do { ! 1234: X = Z; ! 1235: I = 1; ! 1236: SR3980(); ! 1237: if (Z == AInvrse) Break = True; ! 1238: else Z = AInvrse; ! 1239: } while ( ! (Break)); ! 1240: /*=============================================*/ ! 1241: Milestone = 100; ! 1242: /*=============================================*/ ! 1243: /* Powers of Radix have been tested, */ ! 1244: /* next try a few primes */ ! 1245: M = NoTrials; ! 1246: Z = Three; ! 1247: do { ! 1248: X = Z; ! 1249: I = 1; ! 1250: SR3980(); ! 1251: do { ! 1252: Z = Z + Two; ! 1253: } while ( Three * FLOOR(Z / Three) == Z ); ! 1254: } while ( Z < Eight * Three ); ! 1255: if (N > 0) { ! 1256: printf("Errors like this may invalidate financial calculations\n"); ! 1257: printf("\tinvolving interest rates.\n"); ! 1258: } ! 1259: PrintIfNPositive(); ! 1260: N += N1; ! 1261: if (N == 0) printf("... no discrepancis found.\n"); ! 1262: if (N > 0) Pause(); ! 1263: else printf("\n"); ! 1264: /*=============================================*/ ! 1265: /*SPLIT ! 1266: } ! 1267: #include "paranoia.h" ! 1268: part6(){ ! 1269: */ ! 1270: Milestone = 110; ! 1271: /*=============================================*/ ! 1272: printf("Seeking Underflow thresholds UfThold and E0.\n"); ! 1273: D = U1; ! 1274: if (Precision != FLOOR(Precision)) { ! 1275: D = BInvrse; ! 1276: X = Precision; ! 1277: do { ! 1278: D = D * BInvrse; ! 1279: X = X - One; ! 1280: } while ( X > Zero); ! 1281: } ! 1282: Y = One; ! 1283: Z = D; ! 1284: /* ... D is power of 1/Radix < 1. */ ! 1285: do { ! 1286: C = Y; ! 1287: Y = Z; ! 1288: Z = Y * Y; ! 1289: } while ((Y > Z) && (Z + Z > Z)); ! 1290: Y = C; ! 1291: Z = Y * D; ! 1292: do { ! 1293: C = Y; ! 1294: Y = Z; ! 1295: Z = Y * D; ! 1296: } while ((Y > Z) && (Z + Z > Z)); ! 1297: if (Radix < Two) HInvrse = Two; ! 1298: else HInvrse = Radix; ! 1299: H = One / HInvrse; ! 1300: /* ... 1/HInvrse == H == Min(1/Radix, 1/2) */ ! 1301: CInvrse = One / C; ! 1302: E0 = C; ! 1303: Z = E0 * H; ! 1304: /* ...1/Radix^(BIG Integer) << 1 << CInvrse == 1/C */ ! 1305: do { ! 1306: Y = E0; ! 1307: E0 = Z; ! 1308: Z = E0 * H; ! 1309: } while ((E0 > Z) && (Z + Z > Z)); ! 1310: UfThold = E0; ! 1311: E1 = Zero; ! 1312: Q = Zero; ! 1313: E9 = U2; ! 1314: S = One + E9; ! 1315: D = C * S; ! 1316: if (D <= C) { ! 1317: E9 = Radix * U2; ! 1318: S = One + E9; ! 1319: D = C * S; ! 1320: if (D <= C) { ! 1321: BadCond(Failure, "multiplication gets too many last digits wrong.\n"); ! 1322: Underflow = E0; ! 1323: Y1 = Zero; ! 1324: PseudoZero = Z; ! 1325: Pause(); ! 1326: } ! 1327: } ! 1328: else { ! 1329: Underflow = D; ! 1330: PseudoZero = Underflow * H; ! 1331: UfThold = Zero; ! 1332: do { ! 1333: Y1 = Underflow; ! 1334: Underflow = PseudoZero; ! 1335: if (E1 + E1 <= E1) { ! 1336: Y2 = Underflow * HInvrse; ! 1337: E1 = FABS(Y1 - Y2); ! 1338: Q = Y1; ! 1339: if ((UfThold == Zero) && (Y1 != Y2)) UfThold = Y1; ! 1340: } ! 1341: PseudoZero = PseudoZero * H; ! 1342: } while ((Underflow > PseudoZero) ! 1343: && (PseudoZero + PseudoZero > PseudoZero)); ! 1344: } ! 1345: /* Comment line 4530 .. 4560 */ ! 1346: if (PseudoZero != Zero) { ! 1347: printf("\n"); ! 1348: Z = PseudoZero; ! 1349: /* ... Test PseudoZero for "phoney- zero" violates */ ! 1350: /* ... PseudoZero < Underflow or PseudoZero < PseudoZero + PseudoZero ! 1351: ... */ ! 1352: if (PseudoZero <= Zero) { ! 1353: BadCond(Failure, "Positive expressions can underflow to an\n"); ! 1354: printf("allegedly negative value\n"); ! 1355: printf("PseudoZero that prints out as: %g .\n", PseudoZero); ! 1356: X = - PseudoZero; ! 1357: if (X <= Zero) { ! 1358: printf("But -PseudoZero, which should be\n"); ! 1359: printf("positive, isn't; it prints out as %g .\n", X); ! 1360: } ! 1361: } ! 1362: else { ! 1363: BadCond(Flaw, "Underflow can stick at an allegedly positive\n"); ! 1364: printf("value PseudoZero that prints out as %g .\n", PseudoZero); ! 1365: } ! 1366: TstPtUf(); ! 1367: } ! 1368: /*=============================================*/ ! 1369: Milestone = 120; ! 1370: /*=============================================*/ ! 1371: if (CInvrse * Y > CInvrse * Y1) { ! 1372: S = H * S; ! 1373: E0 = Underflow; ! 1374: } ! 1375: if (! ((E1 == Zero) || (E1 == E0))) { ! 1376: BadCond(Defect, ""); ! 1377: if (E1 < E0) { ! 1378: printf("Products underflow at a higher"); ! 1379: printf(" threshold than differences.\n"); ! 1380: if (PseudoZero == Zero) ! 1381: E0 = E1; ! 1382: } ! 1383: else { ! 1384: printf("Difference underflows at a higher"); ! 1385: printf(" threshold than products.\n"); ! 1386: } ! 1387: } ! 1388: printf("Smallest strictly positive number found is E0 = %g .\n", E0); ! 1389: Z = E0; ! 1390: TstPtUf(); ! 1391: Underflow = E0; ! 1392: if (N == 1) Underflow = Y; ! 1393: I = 4; ! 1394: if (E1 == Zero) I = 3; ! 1395: if (UfThold == Zero) I = I - 2; ! 1396: UfNGrad = True; ! 1397: switch (I) { ! 1398: case 1: ! 1399: UfThold = Underflow; ! 1400: if ((CInvrse * Q) != ((CInvrse * Y) * S)) { ! 1401: UfThold = Y; ! 1402: BadCond(Failure, "Either accuracy deteriorates as numbers\n"); ! 1403: printf("approach a threshold = %.17e\n", UfThold);; ! 1404: printf(" coming down from %.17e\n", C); ! 1405: printf(" or else multiplication gets too many last digits wrong.\n"); ! 1406: } ! 1407: Pause(); ! 1408: break; ! 1409: ! 1410: case 2: ! 1411: BadCond(Failure, "Underflow confuses Comparison, which alleges that\n"); ! 1412: printf("Q == Y while denying that |Q - Y| == 0; these values\n"); ! 1413: printf("print out as Q = %.17e, Y = %.17e .\n", Q, Y2); ! 1414: printf ("|Q - Y| = %.17e .\n" , FABS(Q - Y2)); ! 1415: UfThold = Q; ! 1416: break; ! 1417: ! 1418: case 3: ! 1419: X = X; ! 1420: break; ! 1421: ! 1422: case 4: ! 1423: if ((Q == UfThold) && (E1 == E0) ! 1424: && (FABS( UfThold - E1 / E9) <= E1)) { ! 1425: UfNGrad = False; ! 1426: printf("Underflow is gradual; it incurs Absolute Error =\n"); ! 1427: printf("(roundoff in UfThold) < E0.\n"); ! 1428: Y = E0 * CInvrse; ! 1429: Y = Y * (OneAndHalf + U2); ! 1430: X = CInvrse * (One + U2); ! 1431: Y = Y / X; ! 1432: IEEE = (Y == E0); ! 1433: } ! 1434: } ! 1435: if (UfNGrad) { ! 1436: printf("\n"); ! 1437: sigsave = sigfpe; ! 1438: if (setjmp(ovfl_buf)) { ! 1439: printf("Underflow / UfThold failed!\n"); ! 1440: R = H + H; ! 1441: } ! 1442: else R = SQRT(Underflow / UfThold); ! 1443: sigsave = 0; ! 1444: if (R <= H) { ! 1445: Z = R * UfThold; ! 1446: X = Z * (One + R * H * (One + H)); ! 1447: } ! 1448: else { ! 1449: Z = UfThold; ! 1450: X = Z * (One + H * H * (One + H)); ! 1451: } ! 1452: if (! ((X == Z) || (X - Z != Zero))) { ! 1453: BadCond(Flaw, ""); ! 1454: printf("X = %.17e\n\tis not equal to Z = %.17e .\n", X, Z); ! 1455: Z9 = X - Z; ! 1456: printf("yet X - Z yields %.17e .\n", Z9); ! 1457: printf(" Should this NOT signal Underflow, "); ! 1458: printf("this is a SERIOUS DEFECT\nthat causes "); ! 1459: printf("confusion when innocent statements like\n");; ! 1460: printf(" if (X == Z) ... else"); ! 1461: printf(" ... (f(X) - f(Z)) / (X - Z) ...\n"); ! 1462: printf("encounter Division by Zero although actually\n"); ! 1463: sigsave = sigfpe; ! 1464: if (setjmp(ovfl_buf)) printf("X / Z fails!\n"); ! 1465: else printf("X / Z = 1 + %g .\n", (X / Z - Half) - Half); ! 1466: sigsave = 0; ! 1467: } ! 1468: } ! 1469: printf("The Underflow threshold is %.17e, %s\n", UfThold, ! 1470: " below which"); ! 1471: printf("calculation may suffer larger Relative error than "); ! 1472: printf("merely roundoff.\n"); ! 1473: Y2 = U1 * U1; ! 1474: Y = Y2 * Y2; ! 1475: Y2 = Y * U1; ! 1476: if (Y2 <= UfThold) { ! 1477: if (Y > E0) { ! 1478: BadCond(Defect, ""); ! 1479: I = 5; ! 1480: } ! 1481: else { ! 1482: BadCond(Serious, ""); ! 1483: I = 4; ! 1484: } ! 1485: printf("Range is too narrow; U1^%d Underflows.\n", I); ! 1486: } ! 1487: /*=============================================*/ ! 1488: /*SPLIT ! 1489: } ! 1490: #include "paranoia.h" ! 1491: part7(){ ! 1492: */ ! 1493: Milestone = 130; ! 1494: /*=============================================*/ ! 1495: Y = - FLOOR(Half - TwoForty * LOG(UfThold) / LOG(HInvrse)) / TwoForty; ! 1496: Y2 = Y + Y; ! 1497: printf("Since underflow occurs below the threshold\n"); ! 1498: printf("UfThold = (%.17e) ^ (%.17e)\nonly underflow ", HInvrse, Y); ! 1499: printf("should afflict the expression\n\t(%.17e) ^ (%.17e);\n", HInvrse, Y); ! 1500: V9 = POW(HInvrse, Y2); ! 1501: printf("actually calculating yields: %.17e .\n", V9); ! 1502: if (! ((V9 >= Zero) && (V9 <= (Radix + Radix + E9) * UfThold))) { ! 1503: BadCond(Serious, "this is not between 0 and underflow\n"); ! 1504: printf(" threshold = %.17e .\n", UfThold); ! 1505: } ! 1506: else if (! (V9 > UfThold * (One + E9))) ! 1507: printf("This computed value is O.K.\n"); ! 1508: else { ! 1509: BadCond(Defect, "this is not between 0 and underflow\n"); ! 1510: printf(" threshold = %.17e .\n", UfThold); ! 1511: } ! 1512: /*=============================================*/ ! 1513: Milestone = 140; ! 1514: /*=============================================*/ ! 1515: printf("\n"); ! 1516: /* ...calculate Exp2 == exp(2) == 7.389056099... */ ! 1517: X = Zero; ! 1518: I = 2; ! 1519: Y = Two * Three; ! 1520: Q = Zero; ! 1521: N = 0; ! 1522: do { ! 1523: Z = X; ! 1524: I = I + 1; ! 1525: Y = Y / (I + I); ! 1526: R = Y + Q; ! 1527: X = Z + R; ! 1528: Q = (Z - X) + R; ! 1529: } while(X > Z); ! 1530: Z = (OneAndHalf + One / Eight) + X / (OneAndHalf * ThirtyTwo); ! 1531: X = Z * Z; ! 1532: Exp2 = X * X; ! 1533: X = F9; ! 1534: Y = X - U1; ! 1535: printf("Testing X^((X + 1) / (X - 1)) vs. exp(2) = %.17e as X -> 1.\n", ! 1536: Exp2); ! 1537: for(I = 1;;) { ! 1538: Z = X - BInvrse; ! 1539: Z = (X + One) / (Z - (One - BInvrse)); ! 1540: Q = POW(X, Z) - Exp2; ! 1541: if (FABS(Q) > TwoForty * U2) { ! 1542: N = 1; ! 1543: V9 = (X - BInvrse) - (One - BInvrse); ! 1544: BadCond(Defect, "Calculated"); ! 1545: printf(" %.17e for\n", POW(X,Z)); ! 1546: printf("\t(1 + (%.17e) ^ (%.17e);\n", V9, Z); ! 1547: printf("\tdiffers from correct value by %.17e .\n", Q); ! 1548: printf("\tThis much error may spoil financial\n"); ! 1549: printf("\tcalculations involving tiny interest rates.\n"); ! 1550: break; ! 1551: } ! 1552: else { ! 1553: Z = (Y - X) * Two + Y; ! 1554: X = Y; ! 1555: Y = Z; ! 1556: Z = One + (X - F9)*(X - F9); ! 1557: if (Z > One && I < NoTrials) I++; ! 1558: else { ! 1559: if (X > One) { ! 1560: if (N == 0) ! 1561: printf("Accuracy seems adequate.\n"); ! 1562: break; ! 1563: } ! 1564: else { ! 1565: X = One + U2; ! 1566: Y = U2 + U2; ! 1567: Y += X; ! 1568: I = 1; ! 1569: } ! 1570: } ! 1571: } ! 1572: } ! 1573: /*=============================================*/ ! 1574: Milestone = 150; ! 1575: /*=============================================*/ ! 1576: printf("Testing powers Z^Q at four nearly extreme values.\n"); ! 1577: N = 0; ! 1578: Z = A1; ! 1579: Q = FLOOR(Half - LOG(C) / LOG(A1)); ! 1580: Break = False; ! 1581: do { ! 1582: X = CInvrse; ! 1583: Y = POW(Z, Q); ! 1584: IsYeqX(); ! 1585: Q = - Q; ! 1586: X = C; ! 1587: Y = POW(Z, Q); ! 1588: IsYeqX(); ! 1589: if (Z < One) Break = True; ! 1590: else Z = AInvrse; ! 1591: } while ( ! (Break)); ! 1592: PrintIfNPositive(); ! 1593: if (N == 0) printf(" ... no discrepancies found.\n"); ! 1594: printf("\n"); ! 1595: ! 1596: /*=============================================*/ ! 1597: Milestone = 160; ! 1598: /*=============================================*/ ! 1599: Pause(); ! 1600: printf("Searching for Overflow threshold:\n"); ! 1601: printf("This may generate an error.\n"); ! 1602: Y = - CInvrse; ! 1603: V9 = HInvrse * Y; ! 1604: sigsave = sigfpe; ! 1605: if (setjmp(ovfl_buf)) { I = 0; V9 = Y; goto overflow; } ! 1606: do { ! 1607: V = Y; ! 1608: Y = V9; ! 1609: V9 = HInvrse * Y; ! 1610: } while(V9 < Y); ! 1611: I = 1; ! 1612: overflow: ! 1613: sigsave = 0; ! 1614: Z = V9; ! 1615: printf("Can `Z = -Y' overflow?\n"); ! 1616: printf("Trying it on Y = %.17e .\n", Y); ! 1617: V9 = - Y; ! 1618: V0 = V9; ! 1619: if (V - Y == V + V0) printf("Seems O.K.\n"); ! 1620: else { ! 1621: printf("finds a "); ! 1622: BadCond(Flaw, "-(-Y) differs from Y.\n"); ! 1623: } ! 1624: if (Z != Y) { ! 1625: BadCond(Serious, ""); ! 1626: printf("overflow past %.17e\n\tshrinks to %.17e .\n", Y, Z); ! 1627: } ! 1628: if (I) { ! 1629: Y = V * (HInvrse * U2 - HInvrse); ! 1630: Z = Y + ((One - HInvrse) * U2) * V; ! 1631: if (Z < V0) Y = Z; ! 1632: if (Y < V0) V = Y; ! 1633: if (V0 - V < V0) V = V0; ! 1634: } ! 1635: else { ! 1636: V = Y * (HInvrse * U2 - HInvrse); ! 1637: V = V + ((One - HInvrse) * U2) * Y; ! 1638: } ! 1639: printf("Overflow threshold is V = %.17e .\n", V); ! 1640: if (I) printf("Overflow saturates at V0 = %.17e .\n", V0); ! 1641: else printf("There is no saturation value because the system traps on overflow.\n"); ! 1642: V9 = V * One; ! 1643: printf("No Overflow should be signaled for V * 1 = %.17e\n", V9); ! 1644: V9 = V / One; ! 1645: printf(" nor for V / 1 = %.17e .\n", V9); ! 1646: printf("Any overflow signal separating this * from the one\n"); ! 1647: printf("above is a DEFECT.\n"); ! 1648: /*=============================================*/ ! 1649: Milestone = 170; ! 1650: /*=============================================*/ ! 1651: if (!(-V < V && -V0 < V0 && -UfThold < V && UfThold < V)) { ! 1652: BadCond(Failure, "Comparisons involving "); ! 1653: printf("+-%g, +-%g\nand +-%g are confused by Overflow.", ! 1654: V, V0, UfThold); ! 1655: } ! 1656: /*=============================================*/ ! 1657: Milestone = 175; ! 1658: /*=============================================*/ ! 1659: printf("\n"); ! 1660: for(Indx = 1; Indx <= 3; ++Indx) { ! 1661: switch (Indx) { ! 1662: case 1: Z = UfThold; break; ! 1663: case 2: Z = E0; break; ! 1664: case 3: Z = PseudoZero; break; ! 1665: } ! 1666: if (Z != Zero) { ! 1667: V9 = SQRT(Z); ! 1668: Y = V9 * V9; ! 1669: if (Y / (One - Radix * E9) < Z ! 1670: || Y > (One + Radix * E9) * Z) { /* dgh: + E9 --> * E9 */ ! 1671: if (V9 > U1) BadCond(Serious, ""); ! 1672: else BadCond(Defect, ""); ! 1673: printf("Comparison alleges that what prints as Z = %.17e\n", Z); ! 1674: printf(" is too far from sqrt(Z) ^ 2 = %.17e .\n", Y); ! 1675: } ! 1676: } ! 1677: } ! 1678: /*=============================================*/ ! 1679: Milestone = 180; ! 1680: /*=============================================*/ ! 1681: for(Indx = 1; Indx <= 2; ++Indx) { ! 1682: if (Indx == 1) Z = V; ! 1683: else Z = V0; ! 1684: V9 = SQRT(Z); ! 1685: X = (One - Radix * E9) * V9; ! 1686: V9 = V9 * X; ! 1687: if (((V9 < (One - Two * Radix * E9) * Z) || (V9 > Z))) { ! 1688: Y = V9; ! 1689: if (X < W) BadCond(Serious, ""); ! 1690: else BadCond(Defect, ""); ! 1691: printf("Comparison alleges that Z = %17e\n", Z); ! 1692: printf(" is too far from sqrt(Z) ^ 2 (%.17e) .\n", Y); ! 1693: } ! 1694: } ! 1695: /*=============================================*/ ! 1696: /*SPLIT ! 1697: } ! 1698: #include "paranoia.h" ! 1699: part8(){ ! 1700: */ ! 1701: Milestone = 190; ! 1702: /*=============================================*/ ! 1703: Pause(); ! 1704: X = UfThold * V; ! 1705: Y = Radix * Radix; ! 1706: if (X*Y < One || X > Y) { ! 1707: if (X * Y < U1 || X > Y/U1) BadCond(Defect, "Badly"); ! 1708: else BadCond(Flaw, ""); ! 1709: ! 1710: printf(" unbalanced range; UfThold * V = %.17e\n\t%s\n", ! 1711: X, "is too far from 1.\n"); ! 1712: } ! 1713: /*=============================================*/ ! 1714: Milestone = 200; ! 1715: /*=============================================*/ ! 1716: for (Indx = 1; Indx <= 5; ++Indx) { ! 1717: X = F9; ! 1718: switch (Indx) { ! 1719: case 2: X = One + U2; break; ! 1720: case 3: X = V; break; ! 1721: case 4: X = UfThold; break; ! 1722: case 5: X = Radix; ! 1723: } ! 1724: Y = X; ! 1725: sigsave = sigfpe; ! 1726: if (setjmp(ovfl_buf)) ! 1727: printf(" X / X traps when X = %g\n", X); ! 1728: else { ! 1729: V9 = (Y / X - Half) - Half; ! 1730: if (V9 == Zero) continue; ! 1731: if (V9 == - U1 && Indx < 5) BadCond(Flaw, ""); ! 1732: else BadCond(Serious, ""); ! 1733: printf(" X / X differs from 1 when X = %.17e\n", X); ! 1734: printf(" instead, X / X - 1/2 - 1/2 = %.17e .\n", V9); ! 1735: } ! 1736: sigsave = 0; ! 1737: } ! 1738: /*=============================================*/ ! 1739: Milestone = 210; ! 1740: /*=============================================*/ ! 1741: MyZero = Zero; ! 1742: printf("\n"); ! 1743: printf("What message and/or values does Division by Zero produce?\n") ; ! 1744: #ifndef NOPAUSE ! 1745: printf("This can interupt your program. You can "); ! 1746: printf("skip this part if you wish.\n"); ! 1747: printf("Do you wish to compute 1 / 0? "); ! 1748: fflush(stdout); ! 1749: read (KEYBOARD, ch, 8); ! 1750: if ((ch[0] == 'Y') || (ch[0] == 'y')) { ! 1751: #endif ! 1752: sigsave = sigfpe; ! 1753: printf(" Trying to compute 1 / 0 produces ..."); ! 1754: if (!setjmp(ovfl_buf)) printf(" %.7e .\n", One / MyZero); ! 1755: sigsave = 0; ! 1756: #ifndef NOPAUSE ! 1757: } ! 1758: else printf("O.K.\n"); ! 1759: printf("\nDo you wish to compute 0 / 0? "); ! 1760: fflush(stdout); ! 1761: read (KEYBOARD, ch, 80); ! 1762: if ((ch[0] == 'Y') || (ch[0] == 'y')) { ! 1763: #endif ! 1764: sigsave = sigfpe; ! 1765: printf("\n Trying to compute 0 / 0 produces ..."); ! 1766: if (!setjmp(ovfl_buf)) printf(" %.7e .\n", Zero / MyZero); ! 1767: sigsave = 0; ! 1768: #ifndef NOPAUSE ! 1769: } ! 1770: else printf("O.K.\n"); ! 1771: #endif ! 1772: /*=============================================*/ ! 1773: Milestone = 220; ! 1774: /*=============================================*/ ! 1775: Pause(); ! 1776: printf("\n"); ! 1777: { ! 1778: static char *msg[] = { ! 1779: "FAILUREs encountered =", ! 1780: "SERIOUS DEFECTs discovered =", ! 1781: "DEFECTs discovered =", ! 1782: "FLAWs discovered =" }; ! 1783: int i; ! 1784: for(i = 0; i < 4; i++) if (ErrCnt[i]) ! 1785: printf("The number of %-29s %d.\n", ! 1786: msg[i], ErrCnt[i]); ! 1787: } ! 1788: printf("\n"); ! 1789: if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[Defect] ! 1790: + ErrCnt[Flaw]) > 0) { ! 1791: if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[ ! 1792: Defect] == 0) && (ErrCnt[Flaw] > 0)) { ! 1793: printf("The arithmetic diagnosed seems "); ! 1794: printf("Satisfactory though flawed.\n"); ! 1795: } ! 1796: if ((ErrCnt[Failure] + ErrCnt[Serious] == 0) ! 1797: && ( ErrCnt[Defect] > 0)) { ! 1798: printf("The arithmetic diagnosed may be Acceptable\n"); ! 1799: printf("despite inconvenient Defects.\n"); ! 1800: } ! 1801: if ((ErrCnt[Failure] + ErrCnt[Serious]) > 0) { ! 1802: printf("The arithmetic diagnosed has "); ! 1803: printf("unacceptable Serious Defects.\n"); ! 1804: } ! 1805: if (ErrCnt[Failure] > 0) { ! 1806: printf("Potentially fatal FAILURE may have spoiled this"); ! 1807: printf(" program's subsequent diagnoses.\n"); ! 1808: } ! 1809: } ! 1810: else { ! 1811: printf("No failures, defects nor flaws have been discovered.\n"); ! 1812: if (! ((RMult == Rounded) && (RDiv == Rounded) ! 1813: && (RAddSub == Rounded) && (RSqrt == Rounded))) ! 1814: printf("The arithmetic diagnosed seems Satisfactory.\n"); ! 1815: else { ! 1816: if (StickyBit >= One && ! 1817: (Radix - Two) * (Radix - Nine - One) == Zero) { ! 1818: printf("Rounding appears to conform to "); ! 1819: printf("the proposed IEEE standard P"); ! 1820: if ((Radix == Two) && ! 1821: ((Precision - Four * Three * Two) * ! 1822: ( Precision - TwentySeven - ! 1823: TwentySeven + One) == Zero)) ! 1824: printf("754"); ! 1825: else printf("854"); ! 1826: if (IEEE) printf(".\n"); ! 1827: else { ! 1828: printf(",\nexcept for possibly Double Rounding"); ! 1829: printf(" during Gradual Underflow.\n"); ! 1830: } ! 1831: } ! 1832: printf("The arithmetic diagnosed appears to be Excellent!\n"); ! 1833: } ! 1834: } ! 1835: if (fpecount) ! 1836: printf("\nA total of %d floating point exceptions were registered.\n", ! 1837: fpecount); ! 1838: printf("END OF TEST.\n"); ! 1839: } ! 1840: ! 1841: /*SPLIT subs.c ! 1842: #include "paranoia.h" ! 1843: */ ! 1844: ! 1845: /* Sign */ ! 1846: ! 1847: FLOAT Sign (X) ! 1848: FLOAT X; ! 1849: { return X >= 0. ? 1.0 : -1.0; } ! 1850: ! 1851: /* Pause */ ! 1852: ! 1853: Pause() ! 1854: { ! 1855: #ifndef NOPAUSE ! 1856: char ch[8]; ! 1857: ! 1858: printf("\nTo continue, press RETURN"); ! 1859: fflush(stdout); ! 1860: read(KEYBOARD, ch, 8); ! 1861: #endif ! 1862: printf("\nDiagnosis resumes after milestone Number %d", Milestone); ! 1863: printf(" Page: %d\n\n", PageNo); ! 1864: ++Milestone; ! 1865: ++PageNo; ! 1866: } ! 1867: ! 1868: /* TstCond */ ! 1869: ! 1870: TstCond (K, Valid, T) ! 1871: int K, Valid; ! 1872: char *T; ! 1873: { if (! Valid) { BadCond(K,T); printf(".\n"); } } ! 1874: ! 1875: BadCond(K, T) ! 1876: int K; ! 1877: char *T; ! 1878: { ! 1879: static char *msg[] = { "FAILURE", "SERIOUS DEFECT", "DEFECT", "FLAW" }; ! 1880: ! 1881: ErrCnt [K] = ErrCnt [K] + 1; ! 1882: printf("%s: %s", msg[K], T); ! 1883: } ! 1884: ! 1885: /* Random */ ! 1886: /* Random computes ! 1887: X = (Random1 + Random9)^5 ! 1888: Random1 = X - FLOOR(X) + 0.000005 * X; ! 1889: and returns the new value of Random1 ! 1890: */ ! 1891: ! 1892: FLOAT Random() ! 1893: { ! 1894: FLOAT X, Y; ! 1895: ! 1896: X = Random1 + Random9; ! 1897: Y = X * X; ! 1898: Y = Y * Y; ! 1899: X = X * Y; ! 1900: Y = X - FLOOR(X); ! 1901: Random1 = Y + X * 0.000005; ! 1902: return(Random1); ! 1903: } ! 1904: ! 1905: /* SqXMinX */ ! 1906: ! 1907: SqXMinX (ErrKind) ! 1908: int ErrKind; ! 1909: { ! 1910: FLOAT XA, XB; ! 1911: ! 1912: XB = X * BInvrse; ! 1913: XA = X - XB; ! 1914: SqEr = ((SQRT(X * X) - XB) - XA) / OneUlp; ! 1915: if (SqEr != Zero) { ! 1916: if (SqEr < MinSqEr) MinSqEr = SqEr; ! 1917: if (SqEr > MaxSqEr) MaxSqEr = SqEr; ! 1918: J = J + 1.0; ! 1919: BadCond(ErrKind, "\n"); ! 1920: printf("sqrt( %.17e) - %.17e = %.17e\n", X * X, X, OneUlp * SqEr); ! 1921: printf("\tinstead of correct value 0 .\n"); ! 1922: } ! 1923: } ! 1924: ! 1925: /* NewD */ ! 1926: ! 1927: NewD() ! 1928: { ! 1929: X = Z1 * Q; ! 1930: X = FLOOR(Half - X / Radix) * Radix + X; ! 1931: Q = (Q - X * Z) / Radix + X * X * (D / Radix); ! 1932: Z = Z - Two * X * D; ! 1933: if (Z <= Zero) { ! 1934: Z = - Z; ! 1935: Z1 = - Z1; ! 1936: } ! 1937: D = Radix * D; ! 1938: } ! 1939: ! 1940: /* SR3750 */ ! 1941: ! 1942: SR3750() ! 1943: { ! 1944: if (! ((X - Radix < Z2 - Radix) || (X - Z2 > W - Z2))) { ! 1945: I = I + 1; ! 1946: X2 = SQRT(X * D); ! 1947: Y2 = (X2 - Z2) - (Y - Z2); ! 1948: X2 = X8 / (Y - Half); ! 1949: X2 = X2 - Half * X2 * X2; ! 1950: SqEr = (Y2 + Half) + (Half - X2); ! 1951: if (SqEr < MinSqEr) MinSqEr = SqEr; ! 1952: SqEr = Y2 - X2; ! 1953: if (SqEr > MaxSqEr) MaxSqEr = SqEr; ! 1954: } ! 1955: } ! 1956: ! 1957: /* IsYeqX */ ! 1958: ! 1959: IsYeqX() ! 1960: { ! 1961: if (Y != X) { ! 1962: if (N <= 0) { ! 1963: if (Z == Zero && Q <= Zero) ! 1964: printf("WARNING: computing\n"); ! 1965: else BadCond(Defect, "computing\n"); ! 1966: printf("\t(%.17e) ^ (%.17e)\n", Z, Q); ! 1967: printf("\tyielded %.17e;\n", Y); ! 1968: printf("\twhich compared unequal to correct %.17e ;\n", ! 1969: X); ! 1970: printf("\t\tthey differ by %.17e .\n", Y - X); ! 1971: } ! 1972: N = N + 1; /* ... count discrepancies. */ ! 1973: } ! 1974: } ! 1975: ! 1976: /* SR3980 */ ! 1977: ! 1978: SR3980() ! 1979: { ! 1980: do { ! 1981: Q = (FLOAT) I; ! 1982: Y = POW(Z, Q); ! 1983: IsYeqX(); ! 1984: if (++I > M) break; ! 1985: X = Z * X; ! 1986: } while ( X < W ); ! 1987: } ! 1988: ! 1989: /* PrintIfNPositive */ ! 1990: ! 1991: PrintIfNPositive() ! 1992: { ! 1993: if (N > 0) printf("Similar discrepancies have occurred %d times.\n", N); ! 1994: } ! 1995: ! 1996: /* TstPtUf */ ! 1997: ! 1998: TstPtUf() ! 1999: { ! 2000: N = 0; ! 2001: if (Z != Zero) { ! 2002: printf("Since comparison denies Z = 0, evaluating "); ! 2003: printf("(Z + Z) / Z should be safe.\n"); ! 2004: sigsave = sigfpe; ! 2005: if (setjmp(ovfl_buf)) goto very_serious; ! 2006: Q9 = (Z + Z) / Z; ! 2007: printf("What the machine gets for (Z + Z) / Z is %.17e .\n", ! 2008: Q9); ! 2009: if (FABS(Q9 - Two) < Radix * U2) { ! 2010: printf("This is O.K., provided Over/Underflow"); ! 2011: printf(" has NOT just been signaled.\n"); ! 2012: } ! 2013: else { ! 2014: if ((Q9 < One) || (Q9 > Two)) { ! 2015: very_serious: ! 2016: N = 1; ! 2017: ErrCnt [Serious] = ErrCnt [Serious] + 1; ! 2018: printf("This is a VERY SERIOUS DEFECT!\n"); ! 2019: } ! 2020: else { ! 2021: N = 1; ! 2022: ErrCnt [Defect] = ErrCnt [Defect] + 1; ! 2023: printf("This is a DEFECT!\n"); ! 2024: } ! 2025: } ! 2026: sigsave = 0; ! 2027: V9 = Z * One; ! 2028: Random1 = V9; ! 2029: V9 = One * Z; ! 2030: Random2 = V9; ! 2031: V9 = Z / One; ! 2032: if ((Z == Random1) && (Z == Random2) && (Z == V9)) { ! 2033: if (N > 0) Pause(); ! 2034: } ! 2035: else { ! 2036: N = 1; ! 2037: BadCond(Defect, "What prints as Z = "); ! 2038: printf("%.17e\n\tcompares different from ", Z); ! 2039: if (Z != Random1) printf("Z * 1 = %.17e ", Random1); ! 2040: if (! ((Z == Random2) ! 2041: || (Random2 == Random1))) ! 2042: printf("1 * Z == %g\n", Random2); ! 2043: if (! (Z == V9)) printf("Z / 1 = %.17e\n", V9); ! 2044: if (Random2 != Random1) { ! 2045: ErrCnt [Defect] = ErrCnt [Defect] + 1; ! 2046: BadCond(Defect, "Multiplication does not commute!\n"); ! 2047: printf("\tComparison alleges that 1 * Z = %.17e\n", ! 2048: Random2); ! 2049: printf("\tdiffers from Z * 1 = %.17e\n", Random1); ! 2050: } ! 2051: Pause(); ! 2052: } ! 2053: } ! 2054: } ! 2055: ! 2056: notify(s) ! 2057: char *s; ! 2058: { ! 2059: printf("%s test appears to be inconsistent...\n", s); ! 2060: printf(" PLEASE NOTIFY KARPINKSI!\n"); ! 2061: } ! 2062: ! 2063: /*SPLIT msgs.c */ ! 2064: ! 2065: /* Instructions */ ! 2066: ! 2067: msglist(s) ! 2068: char **s; ! 2069: { while(*s) printf("%s\n", *s++); } ! 2070: ! 2071: Instructions() ! 2072: { ! 2073: static char *instr[] = { ! 2074: "Lest this program stop prematurely, i.e. before displaying\n", ! 2075: " `END OF TEST',\n", ! 2076: "try to persuade the computer NOT to terminate execution when an", ! 2077: "error like Over/Underflow or Division by Zero occurs, but rather", ! 2078: "to persevere with a surrogate value after, perhaps, displaying some", ! 2079: "warning. If persuasion avails naught, don't despair but run this", ! 2080: "program anyway to see how many milestones it passes, and then", ! 2081: "amend it to make further progress.\n", ! 2082: "Answer questions with Y, y, N or n (unless otherwise indicated).\n", ! 2083: 0}; ! 2084: ! 2085: msglist(instr); ! 2086: } ! 2087: ! 2088: /* Heading */ ! 2089: ! 2090: Heading() ! 2091: { ! 2092: static char *head[] = { ! 2093: "Users are invited to help debug and augment this program so it will", ! 2094: "cope with unanticipated and newly uncovered arithmetic pathologies.\n", ! 2095: "Please send suggestions and interesting results to", ! 2096: "\tRichard Karpinski", ! 2097: "\tComputer Center U-76", ! 2098: "\tUniversity of California", ! 2099: "\tSan Francisco, CA 94143-0704, USA\n", ! 2100: "In doing so, please include the following information:", ! 2101: #ifdef Single ! 2102: "\tPrecision:\tsingle;", ! 2103: #else ! 2104: "\tPrecision:\tdouble;", ! 2105: #endif ! 2106: "\tVersion:\t10 February 1989;", ! 2107: "\tComputer:\n", ! 2108: "\tCompiler:\n", ! 2109: "\tOptimization level:\n", ! 2110: "\tOther relevant compiler options:", ! 2111: 0}; ! 2112: ! 2113: msglist(head); ! 2114: } ! 2115: ! 2116: /* Characteristics */ ! 2117: ! 2118: Characteristics() ! 2119: { ! 2120: static char *chars[] = { ! 2121: "Running this program should reveal these characteristics:", ! 2122: " Radix = 1, 2, 4, 8, 10, 16, 100, 256 ...", ! 2123: " Precision = number of significant digits carried.", ! 2124: " U2 = Radix/Radix^Precision = One Ulp", ! 2125: "\t(OneUlpnit in the Last Place) of 1.000xxx .", ! 2126: " U1 = 1/Radix^Precision = One Ulp of numbers a little less than 1.0 .", ! 2127: " Adequacy of guard digits for Mult., Div. and Subt.", ! 2128: " Whether arithmetic is chopped, correctly rounded, or something else", ! 2129: "\tfor Mult., Div., Add/Subt. and Sqrt.", ! 2130: " Whether a Sticky Bit used correctly for rounding.", ! 2131: " UnderflowThreshold = an underflow threshold.", ! 2132: " E0 and PseudoZero tell whether underflow is abrupt, gradual, or fuzzy.", ! 2133: " V = an overflow threshold, roughly.", ! 2134: " V0 tells, roughly, whether Infinity is represented.", ! 2135: " Comparisions are checked for consistency with subtraction", ! 2136: "\tand for contamination with pseudo-zeros.", ! 2137: " Sqrt is tested. Y^X is not tested.", ! 2138: " Extra-precise subexpressions are revealed but NOT YET tested.", ! 2139: " Decimal-Binary conversion is NOT YET tested for accuracy.", ! 2140: 0}; ! 2141: ! 2142: msglist(chars); ! 2143: } ! 2144: ! 2145: History() ! 2146: ! 2147: { /* History */ ! 2148: /* Converted from Brian Wichmann's Pascal version to C by Thos Sumner, ! 2149: with further massaging by David M. Gay. */ ! 2150: ! 2151: static char *hist[] = { ! 2152: "The program attempts to discriminate among", ! 2153: " FLAWs, like lack of a sticky bit,", ! 2154: " Serious DEFECTs, like lack of a guard digit, and", ! 2155: " FAILUREs, like 2+2 == 5 .", ! 2156: "Failures may confound subsequent diagnoses.\n", ! 2157: "The diagnostic capabilities of this program go beyond an earlier", ! 2158: "program called `MACHAR', which can be found at the end of the", ! 2159: "book `Software Manual for the Elementary Functions' (1980) by", ! 2160: "W. J. Cody and W. Waite. Although both programs try to discover", ! 2161: "the Radix, Precision and range (over/underflow thresholds)", ! 2162: "of the arithmetic, this program tries to cope with a wider variety", ! 2163: "of pathologies, and to say how well the arithmetic is implemented.", ! 2164: "\nThe program is based upon a conventional radix representation for", ! 2165: "floating-point numbers, but also allows logarithmic encoding", ! 2166: "as used by certain early WANG machines.\n", ! 2167: "BASIC version of this program (C) 1983 by Prof. W. M. Kahan;", ! 2168: "see source comments for more history.", ! 2169: 0}; ! 2170: ! 2171: msglist(hist); ! 2172: } ! 2173: ! 2174: double ! 2175: pow(x, y) /* return x ^ y (exponentiation) */ ! 2176: double x, y; ! 2177: { ! 2178: extern double exp(), frexp(), ldexp(), log(), modf(); ! 2179: double xy, ye; ! 2180: long i; ! 2181: int ex, ey = 0, flip = 0; ! 2182: ! 2183: if (!y) return 1.0; ! 2184: ! 2185: if ((y < -1100. || y > 1100.) && x != -1.) return exp(y * log(x)); ! 2186: ! 2187: if (y < 0.) { y = -y; flip = 1; } ! 2188: y = modf(y, &ye); ! 2189: if (y) xy = exp(y * log(x)); ! 2190: else xy = 1.0; ! 2191: /* next several lines assume >= 32 bit integers */ ! 2192: x = frexp(x, &ex); ! 2193: if (i = ye) for(;;) { ! 2194: if (i & 1) { xy *= x; ey += ex; } ! 2195: if (!(i >>= 1)) break; ! 2196: x *= x; ! 2197: ex *= 2; ! 2198: if (x < .5) { x *= 2.; ex -= 1; } ! 2199: } ! 2200: if (flip) { xy = 1. / xy; ey = -ey; } ! 2201: return ldexp(xy, ey); ! 2202: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.