|
|
1.1 ! root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ ! 2: ! 3: /* ! 4: $Header: b1fun.c,v 1.4 85/08/22 16:48:24 timo Exp $ ! 5: */ ! 6: ! 7: /* Functions defined on numeric values. */ ! 8: ! 9: #include <errno.h> /* For EDOM and ERANGE */ ! 10: ! 11: #include "b.h" ! 12: #include "b0con.h" ! 13: #include "b1obj.h" ! 14: #include "b1num.h" ! 15: ! 16: /* ! 17: * The visible routines here implement predefined B arithmetic operators, ! 18: * taking one or two numeric values as operands, and returning a numeric ! 19: * value. ! 20: * No type checking of operands is done: this must be done by the caller. ! 21: */ ! 22: ! 23: typedef value (*valfun)(); ! 24: typedef rational (*ratfun)(); ! 25: typedef real (*appfun)(); ! 26: typedef double (*mathfun)(); ! 27: ! 28: /* ! 29: * For the arithmetic functions (+, -, *, /) the same action is needed: ! 30: * 1) if both operands are Integral, use function from int_* submodule; ! 31: * 2) if both are Exact, use function from rat_* submodule (after possibly ! 32: * converting one of them from Integral to Rational); ! 33: * 3) otherwise, make both approximate and use function from app_* ! 34: * submodule. ! 35: * The functions performing the appropriate action for each of the submodules ! 36: * are passed as parameters. ! 37: * Division is a slight exception, since i/j can be a rational. ! 38: * See `quot' below. ! 39: */ ! 40: ! 41: Hidden value dyop(u, v, int_fun, rat_fun, app_fun) ! 42: value u, v; ! 43: valfun int_fun; ! 44: ratfun rat_fun; ! 45: appfun app_fun; ! 46: { ! 47: if (Integral(u) && Integral(v)) /* Use integral operation */ ! 48: return (*int_fun)(u, v); ! 49: ! 50: if (Exact(u) && Exact(v)) { ! 51: rational u1, v1, a; ! 52: ! 53: /* Use rational operation */ ! 54: ! 55: u1 = Integral(u) ? mk_rat((integer)u, int_1, 0) : ! 56: (rational) Copy(u); ! 57: v1 = Integral(v) ? mk_rat((integer)v, int_1, 0) : ! 58: (rational) Copy(v); ! 59: a = (*rat_fun)(u1, v1); ! 60: release((value) u1); ! 61: release((value) v1); ! 62: ! 63: if (Denominator(a) == int_1 && Roundsize(a) == 0) { ! 64: integer b = (integer) Copy(Numerator(a)); ! 65: release((value) a); ! 66: return (value) b; ! 67: } ! 68: ! 69: return (value) a; ! 70: } ! 71: ! 72: /* Use approximate operation */ ! 73: ! 74: { ! 75: real u1, v1, a; ! 76: u1 = Approximate(u) ? (real) Copy(u) : (real) approximate(u); ! 77: v1 = Approximate(v) ? (real) Copy(v) : (real) approximate(v); ! 78: a = (*app_fun)(u1, v1); ! 79: release((value) u1); ! 80: release((value) v1); ! 81: ! 82: return (value) a; ! 83: } ! 84: } ! 85: ! 86: ! 87: Hidden integer isum(u, v) integer u, v; { ! 88: return int_sum(u, v); ! 89: } ! 90: ! 91: Visible value sum(u, v) value u, v; { ! 92: if (IsSmallInt(u) && IsSmallInt(v)) ! 93: return mk_integer(SmallIntVal(u) + SmallIntVal(v)); ! 94: return dyop(u, v, (value (*)())isum, rat_sum, app_sum); ! 95: } ! 96: ! 97: Hidden integer idiff(u, v) integer u, v; { ! 98: return int_diff(u, v); ! 99: } ! 100: ! 101: Visible value diff(u, v) value u, v; { ! 102: if (IsSmallInt(u) && IsSmallInt(v)) ! 103: return mk_integer(SmallIntVal(u) - SmallIntVal(v)); ! 104: return dyop(u, v, (value (*)())idiff, rat_diff, app_diff); ! 105: } ! 106: ! 107: Visible value prod(u, v) value u, v; { ! 108: if (IsSmallInt(u) && IsSmallInt(v)) ! 109: return (value) ! 110: mk_int((double)SmallIntVal(u) * (double)SmallIntVal(v)); ! 111: return dyop(u, v, (value (*)())int_prod, rat_prod, app_prod); ! 112: } ! 113: ! 114: ! 115: /* ! 116: * We cannot use int_quot (which performs integer division with truncation). ! 117: * Here is the routine we need. ! 118: */ ! 119: ! 120: Hidden value xxx_quot(u, v) integer u, v; { ! 121: ! 122: if (v == int_0) { ! 123: error(MESS(400, "in i/j, j is zero")); ! 124: return (value) Copy(u); ! 125: } ! 126: ! 127: return mk_exact(u, v, 0); ! 128: } ! 129: ! 130: Visible value quot(u, v) value u, v; { ! 131: return dyop(u, v, xxx_quot, rat_quot, app_quot); ! 132: } ! 133: ! 134: ! 135: /* ! 136: * Unary minus and abs follow the same principle but with only one operand. ! 137: */ ! 138: ! 139: Visible value negated(u) value u; { ! 140: if (IsSmallInt(u)) return mk_integer(-SmallIntVal(u)); ! 141: if (Integral(u)) ! 142: return (value) int_neg((integer)u); ! 143: if (Rational(u)) ! 144: return (value) rat_neg((rational)u); ! 145: return (value) app_neg((real)u); ! 146: } ! 147: ! 148: ! 149: Visible value absval(u) value u; { ! 150: if (Integral(u)) { ! 151: if (Msd((integer)u) < 0) ! 152: return (value) int_neg((integer)u); ! 153: } else if (Rational(u)) { ! 154: if (Msd(Numerator((rational)u)) < 0) ! 155: return (value) rat_neg((rational)u); ! 156: } else if (Approximate(u) && Frac((real)u) < 0) ! 157: return (value) app_neg((real)u); ! 158: ! 159: return Copy(u); ! 160: } ! 161: ! 162: ! 163: /* ! 164: * The remaining operators follow less similar paths and some of ! 165: * them contain quite subtle code. ! 166: */ ! 167: ! 168: Visible value mod(u, v) value u, v; { ! 169: value p, q, m, n; ! 170: ! 171: if (v == (value)int_0 || ! 172: Rational(v) && Numerator((rational)v) == int_0 || ! 173: Approximate(v) && Frac((real)v) == 0) { ! 174: error(MESS(401, "in x mod y, y is zero")); ! 175: return Copy(u); ! 176: } ! 177: ! 178: if (Integral(u) && Integral(v)) ! 179: return (value) int_mod((integer)u, (integer)v); ! 180: ! 181: /* Compute `u-v*floor(u/v)', as in the formal definition of `u mod v'. */ ! 182: ! 183: q = quot(u, v); ! 184: n = floorf(q); ! 185: release(q); ! 186: p = prod(n, v); ! 187: release(n); ! 188: m = diff(u, p); ! 189: release(p); ! 190: ! 191: return m; ! 192: } ! 193: ! 194: ! 195: /* ! 196: * u**v has the most special cases of all the predefined arithmetic functions. ! 197: */ ! 198: ! 199: Visible value power(u, v) value u, v; { ! 200: real ru, rv, rw; ! 201: if (Exact(u) && (Integral(v) || ! 202: /* Next check catches for integers disguised as rationals: */ ! 203: Rational(v) && Denominator((rational)v) == int_1)) { ! 204: rational a; ! 205: integer b = Integral(v) ? (integer)v : Numerator((rational)v); ! 206: /* Now b is really an integer. */ ! 207: ! 208: u = Integral(u) ? (value) mk_rat((integer)u, int_1, 0) : ! 209: Copy(u); ! 210: ! 211: a = rat_power((rational)u, b); ! 212: release(u); ! 213: if (Denominator(a) == int_1) { /* Make integral result */ ! 214: b = (integer) Copy(Numerator(a)); ! 215: release((value) a); ! 216: return (value)b; ! 217: } ! 218: return (value)a; ! 219: } ! 220: ! 221: if (Exact(v)) { ! 222: integer vn, vd; ! 223: int s; ! 224: ru = (real) approximate(u); ! 225: s = (Frac(ru) > 0) - (Frac(ru) < 0); ! 226: ! 227: if (s < 0) rv = app_neg(ru), release((value)ru), ru = rv; ! 228: if (Integral(v)) { ! 229: vn = (integer)v; ! 230: vd = int_1; ! 231: } else { ! 232: vd = Denominator((rational)v); ! 233: if (s < 0 && Even(Lsd(vd))) ! 234: error(MESS(402, "in x**(p/q), x is negative and q is even")); ! 235: vn = Numerator((rational)v); ! 236: } ! 237: if (vn == int_0) { ! 238: release((value)ru); ! 239: return one; ! 240: } ! 241: if (s == 0 && Msd(vn) < 0) { ! 242: error(MESS(403, "in 0**y, y is negative")); ! 243: return (value) ru; ! 244: } ! 245: if (s < 0 && Even(Lsd(vn))) ! 246: s = 1; ! 247: rv = (real) approximate(v); ! 248: rw = app_power(ru, rv); ! 249: release((value)ru), release((value)rv); ! 250: if (s < 0) ru = app_neg(rw), release((value)rw), rw = ru; ! 251: return (value) rw; ! 252: } ! 253: ! 254: /* Everything else: we now know u or v is approximate */ ! 255: ! 256: ru = (real) approximate(u); ! 257: if (Frac(ru) < 0) { ! 258: error(MESS(404, "in x**y, x is negative and y is not exact")); ! 259: return (value) ru; ! 260: } ! 261: rv = (real) approximate(v); ! 262: if (Frac(ru) == 0 && Frac(rv) < 0) { ! 263: error(MESS(405, "in 0**y, y is negative")); ! 264: release((value)rv); ! 265: return (value) ru; ! 266: } ! 267: rw = app_power(ru, rv); ! 268: release((value)ru), release((value)rv); ! 269: return (value) rw; ! 270: } ! 271: ! 272: ! 273: /* ! 274: * floor: for approximate numbers app_floor() is used; ! 275: * for integers it is a no-op; other exact numbers effectively calculate ! 276: * u - (u mod 1). ! 277: */ ! 278: ! 279: Visible value floorf(u) value u; { ! 280: integer quo, rem, v; ! 281: digit div; ! 282: ! 283: if (Integral(u)) return Copy(u); ! 284: if (Approximate(u)) return app_floor((real)u); ! 285: ! 286: /* It is a rational number */ ! 287: ! 288: div = int_ldiv(Numerator((rational)u), Denominator((rational)u), ! 289: &quo, &rem); ! 290: if (div < 0 && rem != int_0) { /* Correction for negative noninteger */ ! 291: v = int_diff(quo, int_1); ! 292: release((value) quo); ! 293: quo = v; ! 294: } ! 295: release((value) rem); ! 296: return (value) quo; ! 297: } ! 298: ! 299: ! 300: /* ! 301: * ceiling x is defined as -floor(-x); ! 302: * and that's how it's implemented, except for integers. ! 303: */ ! 304: ! 305: Visible value ceilf(u) value u; { ! 306: value v; ! 307: if (Integral(u)) return Copy(u); ! 308: u = negated(u); ! 309: v = floorf(u); ! 310: release(u); ! 311: u = negated(v); ! 312: release(v); ! 313: return u; ! 314: } ! 315: ! 316: ! 317: /* ! 318: * round u is defined as floor(u+0.5), which is what is done here, ! 319: * except for integers which are left unchanged. ! 320: */ ! 321: ! 322: Visible value round1(u) value u; { ! 323: value v, w; ! 324: ! 325: if (Integral(u)) return Copy(u); ! 326: ! 327: v = sum(u, (value)rat_half); ! 328: w = floorf(v); ! 329: release(v); ! 330: ! 331: return w; ! 332: } ! 333: ! 334: ! 335: /* ! 336: * u round v is defined as 10**-u * round(v*10**u). ! 337: * A complication is that u round v is always printed with exactly u digits ! 338: * after the decimal point, even if this involves trailing zeros, ! 339: * or if v is an integer. ! 340: * Consequently, the result is always kept as a rational, even if it can be ! 341: * simplified to an integer, and the size field of the rational number ! 342: * (which is made negative to distinguish it from integers, and < -1 to ! 343: * distinguish it from approximate numbers) is used to store the number of ! 344: * significant digits. ! 345: * Thus a size of -2 means a normal rational number, and a size < -2 ! 346: * means a rounded number to be printed with (-2 - length) digits ! 347: * after the decimal point. This last expression can be retrieved using ! 348: * the macro Roundsize(v) which should only be applied to Rational ! 349: * numbers. ! 350: */ ! 351: ! 352: Visible value round2(u, v) value u, v; { ! 353: value w, tenp; ! 354: int i; ! 355: ! 356: if (!Integral(u)) { ! 357: error(MESS(406, "in n round x, n is not an integer")); ! 358: i = 0; ! 359: } else ! 360: i = propintlet(intval(u)); ! 361: ! 362: tenp = tento(i); ! 363: ! 364: v = prod(v, tenp); ! 365: w = round1(v); ! 366: ! 367: release(v); ! 368: v = quot(w, tenp); ! 369: release(w); ! 370: release(tenp); ! 371: ! 372: if (i > 0) { /* Set number of digits to be printed */ ! 373: if (propintlet(-2 - i) < -2) { ! 374: if (Rational(v)) ! 375: Length(v) = -2 - i; ! 376: else if (Integral(v)) { ! 377: w = v; ! 378: v = mk_exact((integer) w, int_1, i); ! 379: release(w); ! 380: } ! 381: } ! 382: } ! 383: ! 384: return v; ! 385: } ! 386: ! 387: ! 388: /* ! 389: * sign u inspects the sign of either u, u's numerator or u's fractional part. ! 390: */ ! 391: ! 392: Visible value signum(u) value u; { ! 393: int s; ! 394: ! 395: if (Exact(u)) { ! 396: if (Rational(u)) ! 397: u = (value) Numerator((rational)u); ! 398: s = u==(value)int_0 ? 0 : Msd((integer)u) < 0 ? -1 : 1; ! 399: } else ! 400: s = Frac((real)u) > 0 ? 1 : Frac((real)u) < 0 ? -1 : 0; ! 401: ! 402: return MkSmallInt(s); ! 403: } ! 404: ! 405: ! 406: /* ! 407: * ~u makes an approximate number of any numerical value. ! 408: */ ! 409: ! 410: Visible value approximate(u) value u; { ! 411: double x, e, expo; ! 412: register int i; ! 413: if (Approximate(u)) return Copy(u); ! 414: if (IsSmallInt(u)) ! 415: x = SmallIntVal(u), expo = 0; ! 416: else if (Rational(u)) { ! 417: rational r = (rational) u; ! 418: integer p = Numerator(r), q; ! 419: double xp, xq; ! 420: int lp, lq; ! 421: if (p == int_0) ! 422: return Copy((value)app_0); ! 423: q = Denominator(r); ! 424: lp = IsSmallInt(p) ? 1 : Length(p); ! 425: lq = IsSmallInt(q) ? 1 : Length(q); ! 426: xp = 0, xq = 0; ! 427: expo = lp - lq; ! 428: if (IsSmallInt(p)) { xp = SmallIntVal(p); --expo; } ! 429: else { ! 430: for (i = Length(p)-1; i >= 0; --i) { ! 431: xp = xp*BASE + Digit(p, i); ! 432: --expo; ! 433: if (xp < -Maxreal/BASE || xp > Maxreal/BASE) ! 434: break; ! 435: } ! 436: } ! 437: if (IsSmallInt(q)) { xq = SmallIntVal(q); ++expo; } ! 438: else { ! 439: for (i = Length(q)-1; i >= 0; --i) { ! 440: xq = xq*BASE + Digit(q, i); ! 441: ++expo; ! 442: if (xq > Maxreal/BASE) ! 443: break; ! 444: } ! 445: } ! 446: x = xp/xq; ! 447: } ! 448: else if (Integral(u)) { ! 449: integer p = (integer) u; ! 450: if (Length(p) == 0) ! 451: return Copy((value)app_0); ! 452: x = 0; ! 453: expo = Length(p); ! 454: for (i = Length(p)-1; i >= 0; --i) { ! 455: x = x*BASE + Digit(p, i); ! 456: --expo; ! 457: if (x < -Maxreal/BASE || x > Maxreal/BASE) ! 458: break; ! 459: } ! 460: } ! 461: while (expo < 0 && fabs(x) > BASE/Maxreal) ++expo, x /= BASE; ! 462: while (expo > 0 && fabs(x) < Maxreal/BASE) --expo, x *= BASE; ! 463: if (expo != 0) { ! 464: expo = expo*twologBASE + 1; ! 465: e = floor(expo); ! 466: x *= .5 * exp((expo-e) * logtwo); ! 467: } ! 468: else ! 469: e = 0; ! 470: return (value) mk_approx(x, e); ! 471: } ! 472: ! 473: ! 474: /* ! 475: * numerator v returns the numerator of v, whenever v is an exact number. ! 476: * For integers, that is v itself. ! 477: */ ! 478: ! 479: Visible value numerator(v) value v; { ! 480: if (!Exact(v)) { ! 481: error(MESS(407, "*/ on approximate number")); ! 482: return zero; ! 483: } ! 484: ! 485: if (Integral(v)) return Copy(v); ! 486: ! 487: return (value) Copy(Numerator((rational)v)); ! 488: } ! 489: ! 490: ! 491: /* ! 492: * /*v returns the denominator of v, whenever v is an exact number. ! 493: * For integers, that is 1. ! 494: */ ! 495: ! 496: Visible value denominator(v) value v; { ! 497: if (!Exact(v)) { ! 498: error(MESS(408, "/* on approximate number")); ! 499: return zero; ! 500: } ! 501: ! 502: if (Integral(v)) return one; ! 503: ! 504: return (value) Copy(Denominator((rational)v)); ! 505: } ! 506: ! 507: ! 508: /* ! 509: * u root v is defined as v**(1/u), where u is usually but need not be ! 510: * an integer. ! 511: */ ! 512: ! 513: Visible value root2(u, v) value u, v; { ! 514: if (u == (value)int_0 || ! 515: Rational(u) && Numerator((rational)u) == int_0 || ! 516: Approximate(u) && Frac((real)u) == 0) { ! 517: error(MESS(409, "in n root x, n is zero")); ! 518: v = Copy(v); ! 519: } else { ! 520: u = quot((value)int_1, u); ! 521: v = power(v, u); ! 522: release(u); ! 523: } ! 524: ! 525: return v; ! 526: } ! 527: ! 528: /* root x is computed more exactly than n root x, by doing ! 529: one iteration step extra. This ~guarantees root(n**2) = n. */ ! 530: ! 531: Visible value root1(v) value v; { ! 532: value r = root2((value)int_2, v); ! 533: value v_over_r, theirsum, result; ! 534: if (Approximate(r) && Frac((real)r) == 0.0) return (value)r; ! 535: v_over_r = quot(v, r); ! 536: theirsum = sum(r, v_over_r), release(r), release(v_over_r); ! 537: result = quot(theirsum, (value)int_2), release(theirsum); ! 538: return result; ! 539: } ! 540: ! 541: /* The rest of the mathematical functions */ ! 542: ! 543: Visible value pi() { return (value) mk_approx(3.141592653589793238463, 0.0); } ! 544: Visible value e() { return (value) mk_approx(2.718281828459045235360, 0.0); } ! 545: ! 546: Hidden value trig(v, fun, zeroflag) value v; mathfun fun; bool zeroflag; { ! 547: real w = (real) approximate(v); ! 548: double expo = Expo(w), frac = Frac(w), x, result; ! 549: extern int errno; ! 550: if (expo <= Minexpo/2) { ! 551: if (zeroflag) return (value) w; /* sin small x = x, etc. */ ! 552: frac = 0, expo = 0; ! 553: } ! 554: release((value)w); ! 555: if (expo > Maxexpo) errno = EDOM; ! 556: else { ! 557: x = ldexp(frac, (int)expo); ! 558: if (x >= Maxtrig || x <= -Maxtrig) errno = EDOM; ! 559: else { ! 560: errno = 0; ! 561: result = (*fun)(x); ! 562: } ! 563: } ! 564: if (errno != 0) { ! 565: if (errno == ERANGE) ! 566: error(MESS(410, "the result is too large to be representable")); ! 567: else if (errno == EDOM) ! 568: error(MESS(411, "x is too large to compute a meaningful result")); ! 569: else error(MESS(412, "math library error")); ! 570: return Copy((value)app_0); ! 571: } ! 572: return (value) mk_approx(result, 0.0); ! 573: } ! 574: ! 575: Visible value sin1(v) value v; { return trig(v, sin, Yes); } ! 576: Visible value cos1(v) value v; { return trig(v, cos, No); } ! 577: Visible value tan1(v) value v; { return trig(v, tan, Yes); } ! 578: ! 579: Visible value atn1(v) value v; { ! 580: real w = (real) approximate(v); ! 581: double expo = Expo(w), frac = Frac(w); ! 582: if (expo <= Minexpo + 2) return (value) w; /* atan of small x = x */ ! 583: release((value)w); ! 584: if (expo > Maxexpo) expo = Maxexpo; ! 585: return (value) mk_approx(atan(ldexp(frac, (int)expo)), 0.0); ! 586: } ! 587: ! 588: Visible value exp1(v) value v; { ! 589: real w = (real) approximate(v); ! 590: real x = app_exp(w); ! 591: release((value)w); ! 592: return (value) x; ! 593: } ! 594: ! 595: Visible value log1(v) value v; { ! 596: real w = (real) approximate(v); ! 597: real x = app_log(w); ! 598: release((value)w); ! 599: return (value) x; ! 600: } ! 601: ! 602: Visible value log2(u, v) value u, v;{ ! 603: value w; ! 604: u = log1(u); ! 605: v = log1(v); ! 606: w = quot(v, u); ! 607: release(u), release(v); ! 608: return w; ! 609: } ! 610: ! 611: Visible value atn2(u, v) value u, v; { ! 612: real ru = (real) approximate(u), rv = (real) approximate(v); ! 613: double uexpo = Expo(ru), ufrac = Frac(ru); ! 614: double vexpo = Expo(rv), vfrac = Frac(rv); ! 615: release((value)ru), release((value)rv); ! 616: if (uexpo > Maxexpo) uexpo = Maxexpo; ! 617: if (vexpo > Maxexpo) vexpo = Maxexpo; ! 618: return (value) mk_approx( ! 619: atan2( ! 620: vexpo < Minexpo ? 0.0 : ldexp(vfrac, (int)vexpo), ! 621: uexpo < Minexpo ? 0.0 : ldexp(ufrac, (int)uexpo)), ! 622: 0.0); ! 623: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.