Annotation of 43BSD/contrib/B/src/bint/b1nuA.c, revision 1.1

1.1     ! root        1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
        !             2: 
        !             3: /*
        !             4:   $Header: b1nuA.c,v 1.4 85/08/22 16:50:25 timo Exp $
        !             5: */
        !             6: 
        !             7: /* Approximate arithmetic */
        !             8: 
        !             9: #include "b.h"
        !            10: #include "b0con.h"
        !            11: #include "b1obj.h"
        !            12: #include "b1num.h"
        !            13: #include "b3err.h" /* For still_ok */
        !            14: 
        !            15: /*
        !            16: For various reasons, on some machines (notably the VAX), the range
        !            17: of the exponent is too small (ca. 1.7E38), and we cope with this by
        !            18: adding a second word which holds the exponent.
        !            19: However, on other machines (notably the IBM PC), the range is sufficient
        !            20: (ca. 1E300), and here we try to save as much code as possible by not
        !            21: doing our own exponent handling.  (To be fair, we also don't check
        !            22: certain error conditions, to save more code.)
        !            23: The difference is made by #defining EXT_RANGE (in b1num.h), meaning we
        !            24: have to EXTend the RANGE of the exponent.
        !            25: */
        !            26: 
        !            27: #ifdef EXT_RANGE
        !            28: Hidden struct real app_0_buf = {Num, 1, -1, 0.0, -(double)Maxint};
        !            29:        /* Exponent must be less than any realistic exponent! */
        !            30: #else !EXT_RANGE
        !            31: Hidden struct real app_0_buf = {Num, 1, -1, 0.0};
        !            32: #endif !EXT_RANGE
        !            33: 
        !            34: Visible real app_0 = &app_0_buf;
        !            35: 
        !            36: /*
        !            37:  * Build an approximate number.
        !            38:  */
        !            39: 
        !            40: Visible real mk_approx(frac, expo) double frac, expo; {
        !            41:        real u;
        !            42: #ifdef EXT_RANGE
        !            43:        expint e;
        !            44:        if (frac != 0) frac = frexp(frac, &e), expo += e;
        !            45:        if (frac == 0.5) frac = 1, --expo; /* Assert 0.5 < frac <= 1 */
        !            46:        if (frac == 0 || expo < -BIG) return (real) Copy(app_0);
        !            47:        if (expo > BIG) {
        !            48:                error(MESS(700, "approximate number too large"));
        !            49:                expo = BIG;
        !            50:        }
        !            51: #else !EXT_RANGE
        !            52:        if (frac == 0.0) return (real) Copy(app_0);
        !            53:        frac= ldexp(frac, (int)expo);
        !            54: #endif EXT_RANGE
        !            55:        u = (real) grab_num(-1);
        !            56:        Frac(u) = frac;
        !            57: #ifdef EXT_RANGE
        !            58:        Expo(u) = expo;
        !            59: #endif EXT_RANGE
        !            60:        return u;
        !            61: }
        !            62: 
        !            63: /*
        !            64:  * Approximate arithmetic.
        !            65:  */
        !            66: 
        !            67: Visible real app_sum(u, v) real u, v; {
        !            68: #ifdef EXT_RANGE
        !            69:        real w;
        !            70:        if (Expo(u) < Expo(v)) w = u, u = v, v = w;
        !            71:        if (Expo(v) - Expo(u) < Minexpo) return (real) Copy(u);
        !            72:        return mk_approx(Frac(u) + ldexp(Frac(v), (int)(Expo(v) - Expo(u))),
        !            73:                Expo(u));
        !            74: #else !EXT_RANGE
        !            75:        return mk_approx(Frac(u) + Frac(v), 0.0);
        !            76: #endif !EXT_RANGE
        !            77: }
        !            78: 
        !            79: Visible real app_diff(u, v) real u, v; {
        !            80: #ifdef EXT_RANGE
        !            81:        real w;
        !            82:        int sign = 1;
        !            83:        if (Expo(u) < Expo(v)) w = u, u = v, v = w, sign = -1;
        !            84:        if (Expo(v) - Expo(u) < Minexpo)
        !            85:                return sign < 0 ? app_neg(u) : (real) Copy(u);
        !            86:        return mk_approx(
        !            87:                sign * (Frac(u) - ldexp(Frac(v), (int)(Expo(v) - Expo(u)))),
        !            88:                Expo(u));
        !            89: #else !EXT_RANGE
        !            90:        return mk_approx(Frac(u) - Frac(v), 0.0);
        !            91: #endif !EXT_RANGE
        !            92: }
        !            93: 
        !            94: Visible real app_neg(u) real u; {
        !            95:        return mk_approx(-Frac(u), Expo(u));
        !            96: }
        !            97: 
        !            98: Visible real app_prod(u, v) real u, v; {
        !            99:        return mk_approx(Frac(u) * Frac(v), Expo(u) + Expo(v));
        !           100: }
        !           101: 
        !           102: Visible real app_quot(u, v) real u, v; {
        !           103:        if (Frac(v) == 0.0) {
        !           104:                error(MESS(701, "in u/v, v is zero"));
        !           105:                return (real) Copy(u);
        !           106:        }
        !           107:        return mk_approx(Frac(u) / Frac(v), Expo(u) - Expo(v));
        !           108: }
        !           109: 
        !           110: /*
        !           111:        YIELD log"(frac, expo):
        !           112:                CHECK frac > 0
        !           113:                RETURN normalize"(expo*logtwo + log(frac), 0)
        !           114: */
        !           115: 
        !           116: Visible real app_log(v) real v; {
        !           117:        double frac = Frac(v), expo = Expo(v);
        !           118:        if (frac <= 0) {
        !           119:                error(MESS(702, "in log x, x is <= 0"));
        !           120:                return (real) Copy(app_0);
        !           121:        }
        !           122:        return mk_approx(expo*logtwo + log(frac), 0.0);
        !           123: }
        !           124: 
        !           125: /*
        !           126:        YIELD exp"(frac, expo):
        !           127:                IF expo < minexpo: RETURN zero"
        !           128:                WHILE expo < 0: PUT frac/2, expo+1 IN frac, expo
        !           129:                PUT exp frac IN f
        !           130:                PUT normalize"(f, 0) IN f, e
        !           131:                WHILE expo > 0:
        !           132:                        PUT (f, e) prod" (f, e) IN f, e
        !           133:                        PUT expo-1 IN expo
        !           134:                RETURN f, e
        !           135: */
        !           136: 
        !           137: Visible real app_exp(v) real v; {
        !           138: #ifdef EXT_RANGE
        !           139:        expint ei;
        !           140:        double frac = Frac(v), expo = Expo(v), new_expo;
        !           141:        static double canexp;
        !           142:        if (!canexp) canexp = floor(log(log(Maxreal)) / logtwo);
        !           143:        if (expo <= canexp) {
        !           144:                if (expo < Minexpo) return mk_approx(1.0, 0.0);
        !           145:                frac = ldexp(frac, (int)expo);
        !           146:                expo = 0;
        !           147:        }
        !           148:        else if (expo >= Maxexpo) {
        !           149:                /* Definitely too big (the real boundary is much smaller
        !           150:                   but here we are in danger of overflowing new_expo
        !           151:                   in the loop below) */
        !           152:                return mk_approx(1.0, Maxreal); /* Force an error! */
        !           153:        }
        !           154:        else {
        !           155:                frac = ldexp(frac, (int)canexp);
        !           156:                expo -= canexp;
        !           157:        }
        !           158:        frac = exp(frac);
        !           159:        new_expo = 0;
        !           160:        while (expo > 0 && frac != 0) {
        !           161:                frac = frexp(frac, &ei);
        !           162:                new_expo += ei;
        !           163:                frac *= frac;
        !           164:                new_expo += new_expo;
        !           165:                --expo;
        !           166:        }
        !           167:        return mk_approx(frac, new_expo);
        !           168: #else !EXT_RANGE
        !           169:        return mk_approx(exp(Frac(v)), 0.0);
        !           170: #endif !EXT_RANGE
        !           171: }
        !           172: 
        !           173: /*
        !           174:        YIELD (frac, expo) power" v":
        !           175:                \   (f*2**e)**v =
        !           176:                \ = f**v * 2**(e*v) =
        !           177:                \ = f**v * 2**((e*v) mod 1) * 2**floor(e*v) .
        !           178:                PUT exp"(v" prod" normalize"(log frac, 0)) IN temp1" \ = f**v
        !           179:                PUT expo*numval(v") IN ev \ = e*v
        !           180:                PUT exp(logtwo * (ev - floor ev))) IN temp2 \ = 2**(ev mod 1)
        !           181:                PUT temp1" IN f, e
        !           182:                RETURN normalize"(f*temp2, e + floor ev)
        !           183: */
        !           184: 
        !           185: Visible real app_power(u, v) real u, v; {
        !           186:        double frac = Frac(u);
        !           187: #ifdef EXT_RANGE
        !           188:        real logfrac, vlogfrac, result;
        !           189:        double expo = Expo(u), rest;
        !           190: #endif !EXT_RANGE
        !           191:        if (frac <= 0) {
        !           192:                if (frac < 0) error(MESS(703, "in 0**v, v is negative"));
        !           193:                if (v == app_0) return mk_approx(1.0, 0.0); /* 0**0 = 1 */
        !           194:                return (real) Copy(app_0); /* 0**x = 0 */
        !           195:        }
        !           196: #ifdef EXT_RANGE
        !           197:        frac *= 2, expo -= 1; /* Renormalize to 1 < frac <= 2, so log frac > 0 */
        !           198:        logfrac = mk_approx(log(frac), 0.0);
        !           199:        vlogfrac = app_prod(v, logfrac);
        !           200:        result = app_exp(vlogfrac);
        !           201:        /* But what if result overflows but expo is very negative??? */
        !           202:        if (still_ok) {
        !           203:                expo *= numval((value)v);
        !           204:                rest = expo - floor(expo);
        !           205:                frac = Frac(result) * exp(logtwo*rest);
        !           206:                expo = Expo(result) + floor(expo);
        !           207:        }
        !           208:        release((value)logfrac), release((value)vlogfrac), release((value)result);
        !           209:        return mk_approx(frac, expo);
        !           210: #else !EXT_RANGE
        !           211:        return mk_approx(exp(log(frac) * Frac(v)), 0.0);
        !           212: #endif !EXT_RANGE
        !           213: }
        !           214: 
        !           215: Visible int app_comp(u, v) real u, v; {
        !           216:        double xu, xv;
        !           217: #ifdef EXT_RANGE
        !           218:        double eu, ev;
        !           219: #endif EXT_RANGE
        !           220:        if (u == v) return 0;
        !           221:        xu = Frac(u), xv = Frac(v);
        !           222: #ifdef EXT_RANGE
        !           223:        if (xu*xv > 0) {
        !           224:                eu = Expo(u), ev = Expo(v);
        !           225:                if (eu < ev) return xu < 0 ? 1 : -1;
        !           226:                if (eu > ev) return xu < 0 ? -1 : 1;
        !           227:        }
        !           228: #endif EXT_RANGE
        !           229:        if (xu < xv) return -1;
        !           230:        if (xu > xv) return 1;
        !           231:        return 0;
        !           232: }
        !           233: 
        !           234: Visible value app_floor(u) real u; {
        !           235: #ifdef EXT_RANGE
        !           236:        integer v, w;
        !           237:        value twotow, result;
        !           238:        if (Expo(u) <= Dblbits)
        !           239:                return (value)
        !           240:                        mk_int(floor(ldexp(Frac(u),
        !           241:                                (int)(Expo(u) < 0 ? -1 : Expo(u)))));
        !           242:        v = mk_int(ldexp(Frac(u), Dblbits));
        !           243:        w = mk_int(Expo(u) - Dblbits);
        !           244:        twotow = power((value)int_2, (value)w);
        !           245:        result = prod((value)v, twotow);
        !           246:        release((value) v), release((value) w), release(twotow);
        !           247:        if (!Integral(result)) syserr(MESS(704, "app_floor: result not integral"));
        !           248:        return result;
        !           249: #else !EXT_RANGE
        !           250:        return (value) mk_int(floor(Frac(u)));
        !           251: #endif !EXT_RANGE
        !           252: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.