koreth@ssyx.ucsc.edu (Steven Grimm) (06/04/89)
Submitted-by: dbrooks@osf.org (David Brooks) Posting-number: Volume 2, Issue 41 Archive-name: fplib20/part01 This is revision 2.0 of FPLIB, a full floating-point library for use with Sozobon C on the Atari ST. It fixes some minor bugs in revision 1.0, improves the accuracy and speed of all floating point operations, and includes better documentation. #!/bin/sh # shar: Shell Archiver (v1.22) # # This is part 1 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # # Run the following text with /bin/sh to create: # ATOF.C # DNOTES # EXP.C # FABS.C # FMOD.C # FPADD.S # FPCMP.S # FPDIV.S # FPLIB.H # FPMUL.S # FP_PRT.C # ITRIG.C # LIBM.uue # LOG.C # MATH.H # POW.C # README # RNOTES # SPECS # SQRT.C # TRIG.C # if test -r s2_seq_.tmp then echo "Must unpack archives in sequence!" next=`cat s2_seq_.tmp`; echo "Please unpack part $next next" exit 1; fi sed 's/^X//' << 'SHAR_EOF' > ATOF.C && X/* ATOF function for Sozobon C. */ X/* Copyright = David Brooks, 1989 All Rights Reserved */ X X/* Hack warning. Hack warning. Hack warning... */ X/* Somehow I feel scanf should call atof, not the other way around. */ X/* Guys??? */ X Xfloat atof(s) Xchar *s; X{ float res; X X sscanf(s, "%g", &res); X return res; X} X X_scandum() X{ X _scanf(); /* Force floating version to load */ X} SHAR_EOF chmod 0600 ATOF.C || echo "restore of ATOF.C fails" sed 's/^X//' << 'SHAR_EOF' > DNOTES && X Design notes for FPLIB Release 2.0 X ================================== X X XNUMBER REPRESENTATION X--------------------- X XThe floating point format used is Motorola's "Fast Floating Point": X X ----------------------------------------- X | 24 bits mantissa |S| 7 bits exp | X ----------------------------------------- X XThe mantissa has an implicit binary point just off to the left. The Xexponent is binary, stored excess-64. In other words, the actual Xmathematical exponent has 64 added, and the resulting 7-bit number is Xunsigned. X XNegative numbers are stored as sign-and-magnitude. X XAll floating-point operations expect normalized numbers, and generate Xnormalized numbers if the inputs are normalized. A number is Xnormalized if the most significant bit is 1 (except for 0.0, which is Xstored as 32 bits of zero, never negative). Also, a nonzero mantissa Xwith a biased exponent of 0 is not normalized, letting us test the low Xbyte or whole long as a test for 0.0. This all means that the most Xsignificant bit is actually redundant, and could be left off, giving Xone extra bit of precision. Oh well. X XSome of these routines make use of the assumption that all arguments Xare normalized, and may generate slightly bogus results if that isn't Xtrue. Release 1.0 assumed that a biased exponent of zero could have Xa nonzero mantissa; that has been fixed. X XSome examples: 1.0 is hex 80000041 , or 0.5 * 2 ** 1 (binary 0.1, Xexponent 1 + bias of 64). -0.75 is hex C00000C0 (note the sign bit is Xinverted, but no other bit is). X X XACCURACY AND LIMITS X------------------- X XThe accuracy is in the 24-bit mantissa, which gives between 7.22 and X7.52 decimal digits of relative error. Decimal constants are given to X8 digits, and the compiler is trusted to convert them right (it Xgenerally does a reasonable job). X XThe range is in the exponent. The smallest nonzero and largest Xpositive normalized numbers are ~5.4e-20 and ~9.2e18. X XRounding of ambiguous numbers uses round-to-even (see D. E. Knuth's XSeminumerical Algorithms for a discussion on this). This means that Xif the trailing portion is exactly one half of the least significant Xbit, the lsb is forced to be the nearer even number. We often keep Xseveral insignificant bits to be sure this is done correctly. X X XCODING TRICKS X------------- X XIt's quite normal in a library of this type to resort to bit-twiddling Xin the internal representation. To help this, FPLIB.H defines a C Xunion, thus: X Xunion { X unsigned long ul; X float f; X char sc[4]; X }; X XThe number can be looked at as a floating or integer long (for handling Xbits in the mantissa), the sign is the sign of sc[3], and the exponent Xis the rest of sc[3]. Other shortcuts are commented in the inividual Xroutines. X X XMATHEMATICAL INFORMATION X------------------------ X XWell, this is mostly what I remember from my undergraduate days. Many Xof these functions have a precise mathematical formula or algorithm Xthat will give the result, but is too slow for practical use. Instead, Xwe look for an approximation that is quick to compute, and gives us Xjust enough precision and no more. After all, why compute to 100 Xdigits accuracy when you can only represent less than 8? Some of these Xapproximations look very strange, but they all have sound mathematical Xbases. The name Chebyshev springs to mind. X XDedicated mathematicians have struggled for decades to bring you these Xformulae and, just as important, a predictable accuracy of better than X7.5 decimal digits. Because of this, we can execute a known number of Xoperations instead of loop-and-test (as you would in, for example, a Xsimple Newton's iteration for square root). X XThe approximations are generally polynomials, usually avoid division, and Xare valid only over a small range of the input parameter. We use simple Xmathematical identities to extend the range. For example, the cyclic Xnature of the trigonometric functions means we only need calculate in the Xrange 0..pi/2. For another example, we can do much of the square root Xcalculation by the simple expedient of dividing the binary exponent by 2. X X XRANDOM LIBRARY INFORMATION X-------------------------- X XRelease 1.0 of Sozobon C had a few problems in the floating support: X X- Two negative floating numbers compared wrong (returned > when it X should be <). I corrected that. However, the other routines don't X assume the correction has been installed in the library (which it X wasn't, at first...). X X- The library was not optimally ordered, and had to be scanned twice. X I straightened that out. X X- Add and subtract were truncating. Rounding is generally a better idea. X Xatof() calls sscanf(). Ick. X X------------------------------------------------------------------------------- X XThese routines may be used without restriction, but I retain the copyright Xon them, and the Only True Upgrades will be those I make. If you have any Ximprovements, please send them to me. X XMarch 1989 X XDavid W. Brooks X36 Elm Street XMedfield, MA 02052 X XBROOKS@CSSS-A.PRIME.COM X{uunet,mit-eddie}!csss-a.prime.com!brooks SHAR_EOF chmod 0600 DNOTES || echo "restore of DNOTES fails" sed 's/^X//' << 'SHAR_EOF' > EXP.C && X/* EXP and hyperbolic trig functions for Sozobon C. */ X/* Copyright = David Brooks, 1989 All Rights Reserved */ X X#include <fplib.h> X#include <errno.h> X X/* EXP: */ X/* */ X/* Uses the synthesis (2**n) * (2**[m/8]) * b**g */ X/* where b = 2**(1/8) and 8*n+m+g = arg/ln(b). b**g has a cubic */ X/* approximation: source and accuracy unknown. */ X/* */ X/* Beware a bug in the standard release: can't compare two negative */ X/* floating numbers. */ X Xfloat exp(a) register float a; X{ fstruct res; X register int aint; X X static fstruct huge = {HUGE_AS_INT}; X static float powtab[] = {1.0, 1.09050773, 1.1892071, 1.2968396, X 1.41421356, 1.5422108, 1.68179283, 1.8340081}; X X if (a > 43.5) X { errno = ERANGE; X return huge.f; X } X X if ((a + 43.5) < 0.0) X return 0.0; /* Underflow */ X X if ((aint = (int)(a *= 11.5415603)) < 0) /* 8/ln(2) */ X --aint; /* Correct mathematically */ X a = (float)aint - a; /* -(frac part) */ X X res.f = 1.0 + a * (-0.0866439378 + a * (0.003750577 + X a * -0.11321783e-3)); X res.sc[3] += aint >> 3; /* Mult by 2**n */ X return res.f * powtab[aint&7]; /* Mult by 2**[m/8] */ X} X X/* HYPERBOLIC FUNCTIONS: virtually free */ X Xfloat sinh(a) float a; X{ register float ea = exp(a); X X return 0.5 * (ea - (1.0 / ea)); X} X Xfloat cosh(a) float a; X{ register float ea = exp(a); X X return 0.5 * (ea + (1.0 / ea)); X} X Xfloat tanh(a) float a; X{ register float e2a; X X e2a = exp(a); X e2a = e2a * e2a; /* exp-squared-a */ X return (e2a - 1.0) / (e2a + 1.0); X} X SHAR_EOF chmod 0600 EXP.C || echo "restore of EXP.C fails" sed 's/^X//' << 'SHAR_EOF' > FABS.C && X/* FABS, LDEXP, and FREXP functions for Sozobon C. */ X/* Copyright = David Brooks, 1989 All Rights Reserved */ X X/* Mustn't allow the standard declaration of fabs()... */ X#define MATH_H X X#include <fplib.h> X#include <errno.h> X X/* FABS: directly manipulate the sign bit, punning the type. Actually */ X/* the argument and return are both float. */ X Xunsigned long fabs(a) Xunsigned long a; X{ return a & 0xFFFFFF7FL; } X X/* LDEXP: again direct manipulation. */ X Xfloat ldexp(a, n) Xfstruct a; Xint n; X{ X/* "long" to handle int overflow/underflow... */ X register long exp = (long)(a.sc[3] & EXP_MASK) + n; X X if (exp <= 0L) X return 0L; /* Underflow */ X X if (exp > 0x7FL) X { errno = ERANGE; /* Overflow */ X a.ul |= 0xFFFFFF7FL; /* Preserve sign */ X return a.f; X } X X a.sc[3] = (a.sc[3] & 0x80) | exp; X return a.f; X} X X/* FREXP: split into convenient mantissa and exponent */ X Xfloat frexp(a, ip) Xfstruct a; Xint *ip; X{ if (a.sc[3] == 0) X *ip = 0; X else X { *ip = (a.sc[3] & 0x7f) - BIAS; X a.sc[3] = (a.sc[3] & 0x80) | BIAS; /* preserve sign, X force exponent */ X } X X return a.f; X} SHAR_EOF chmod 0600 FABS.C || echo "restore of FABS.C fails" sed 's/^X//' << 'SHAR_EOF' > FMOD.C && X/* CEIL, FLOOR, MODF, and FMOD functions for Sozobon C. */ X/* Copyright = David Brooks, 1989 All Rights Reserved */ X X#include <fplib.h> X X/* This macro returns true if the number is so large that is has no */ X/* representable fraction. */ X X#define ISLGINT(a) (((a).sc[3] & EXP_MASK) > (BIAS + MANT_BITS)) X X/* CEIL: smallest integral value not less than a. */ X Xfloat ceil(a) Xfstruct a; X{ register float aint; X X if (ISLGINT(a)) X return a.f; X X if ((aint = (float)((long)a.f)) != a.f && a.sc[3] >= 0) X ++aint; X X return aint; X} X X/* FLOOR: largest integral value not greater than a. */ X Xfloat floor(a) Xfstruct a; X{ register float aint; X X if (ISLGINT(a)) X return a.f; X X if ((aint = (float)((long)a.f)) != a.f && a.sc[3] < 0) X --aint; X X return aint; X} X X/* Just for once, we luck out: negative numbers behave as needed... */ X Xfloat modf(a, ip) Xfstruct a; Xfloat *ip; X{ long ipart; X X *ip = (ISLGINT(a))?a.f:(float)(long)a.f; X X return a.f - *ip; X} X Xfloat fmod(n, d) Xfloat n, d; X{ fstruct quot; X long iquot; X X quot.f = n / d; X if (ISLGINT(quot)) X return 0.0; X X iquot = (long)quot.f; X return n - (float)iquot * d; X} SHAR_EOF chmod 0600 FMOD.C || echo "restore of FMOD.C fails" sed 's/^X//' << 'SHAR_EOF' > FPADD.S && X* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg X* X* Permission is granted to anyone to use this software for any purpose X* on any computer system, and to redistribute it freely, with the X* following restrictions: X* 1) No charge may be made other than reasonable charges for reproduction. X* 2) Modified versions must be clearly marked as such. X* 3) The authors are not responsible for any harmful consequences X* of using this software, even if they result from defects in it. X* X* X* MODIFICATIONS: X* X* D.W.Brooks Mar 89 Implemented rounding, inlined one-call subroutines, X* and several other speedups X* X* Rounding in the ambiguous case (tail byte = 0x80) uses round-to-even, as X* Knuth insists (TAOCP3SNA). X* X* fpsub X* X .globl fpsub X .globl _fpsub Xfpsub: X_fpsub: X eor.b #$80,11(sp) * negate B, fall through (can produce -0.0) X* X* fpadd X* X .globl fpadd X .globl _fpadd Xfpadd: X_fpadd: X move.l d3,a1 * save d3 X move.l d4,a2 * and d4 X move.l 4(sp),d0 * First arg X move.l 8(sp),d1 * Second arg X move.l d0,d4 * Keeps the result's sign X moveq.l #$7f,d3 X X move.b d0,d2 * Compare signs only X eor.b d1,d2 X bpl same_sign X* different signs X and.b d3,d0 * Force positive X and.b d3,d1 X X move.l d0,d2 * note d2 is copy of d0 X cmp.b d0,d1 * Compare magnitudes X bne sk1 X cmp.l d0,d1 Xsk1: X ble norev1 X move.l d1,d0 * swap d0/d1...d0 was saved in d2... X move.l d2,d1 X move.b d0,d2 * ...now d2.b is copy of new d0.b X not.b d4 * Invert sign Xnorev1: X* Begin unsigned subtract. Here we have (d0-d1), d0 >= d1, both positive. X* d2.b has result exp. Subtract 0.0 works without needing a special case. X X move.b d0,d3 X sub.b d1,d3 * diff of exps (in low byte) X X clr.b d0 * Extract mantissas X clr.b d1 X X cmp.b #25,d3 X bgt out * Nonsignificant addend: d0 is correct mantissa X lsr.l d3,d1 * Shift uses d3 mod 64 X sub.l d1,d0 X X beq out0 * Zero: all done! X bmi outsub * Already normalized X* normalize loop Xnloop: X subq.b #1,d2 X ble underfl X add.l d0,d0 X bpl nloop X Xoutsub: X add.l #$80,d0 * Force a rounding step. This can't overflow. X * (rum-ti-rum...can it?) X* X* Common exit point for checking rounding after adding 0x80. If the tail X* was not 0x80, it's already the correct result. Otherwise, the tail is now X* 0, and we implement the round-to-even. X* Xoutround: X tst.b d0 X bne out X and.w #$FE00,d0 X* X* Common exit point. d0 has the mantissa, d2 the exponent and d4 the sign. X* Xout: X move.b d2,d0 X and.b #$80,d4 X or.b d4,d0 * fix sign X* X* Come here when d0 has the result X* Xout0: X move.l a1,d3 * restore X move.l a2,d4 X rts X X* underflow Xunderfl: X moveq.l #0,d0 X bra out0 X* X* same signs: do add. X* Xsame_sign: X and.b d3,d0 * Force both positive X and.b d3,d1 X X move.l d0,d2 X cmp.b d0,d1 * Compare magnitudes X bne sk2 X cmp.l d0,d1 Xsk2: X ble norev2 X move.l d1,d0 * Swap d0/d1... X move.l d2,d1 X move.b d0,d2 * ...and d2.b is a copy of d0.b Xnorev2: X* Begin unsigned add: (d0+d1), d0 >= d1 X sub.b d1,d0 X move.b d0,d3 * diff of exps X X clr.b d0 * Extract mantissas X clr.b d1 X X cmp.b #25,d3 X bge out * Nonsignificant addend: d0 has result mantissa X lsr.l d3,d1 X add.l d1,d0 X bcc around X roxr.l #1,d0 * Mantissa overflowed the word X addq.b #1,d2 X bmi oflo * Exponent too hot to handle X Xaround: * Round the fraction. X add.l #$80,d0 * This rounds unless d0.b was 0x80 X bcc outround * No overflow, but do final rounding X roxr.l #1,d0 * Actually loads 0x800000nn X addq.b #1,d2 * Compensate X bpl out * Ok if no exponent overflow X Xoflo: X moveq.l #$ffffffff,d0 * Handle exponent overflow, maintaining sign X moveq.l #$7f,d2 X bra out X X .end SHAR_EOF chmod 0600 FPADD.S || echo "restore of FPADD.S fails" sed 's/^X//' << 'SHAR_EOF' > FPCMP.S && X* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg X* X* Permission is granted to anyone to use this software for any purpose X* on any computer system, and to redistribute it freely, with the X* following restrictions: X* 1) No charge may be made other than reasonable charges for reproduction. X* 2) Modified versions must be clearly marked as such. X* 3) The authors are not responsible for any harmful consequences X* of using this software, even if they result from defects in it. X* X* MODIFICATIONS: X* X* D.W.Brooks 3/5/89 Fixed fpcmp (when both -ve) and fpneg (when zero) X* X X .globl fpcmp X .globl _fpcmp Xfpcmp: X_fpcmp: X move.l 4(sp),d0 X move.l 8(sp),d1 X* Start DWB X move.b d0,d2 * See if both signs are negative X and.b d1,d2 X bpl L0 X move.l d0,d2 * They are: switch arguments so the rest works X move.l d1,d0 X move.l d2,d1 XL0: X* End DWB X cmp.b d1,d0 X bne L1 X cmp.l d1,d0 XL1: X rts X X .globl fpneg X .globl _fpneg Xfpneg: X_fpneg: X move.l 4(sp),d0 X X* DWB removed: tst.b d0 (unnecessary to test for 0.0) X X beq L2 X eor.b #$80,d0 XL2: X rts SHAR_EOF chmod 0600 FPCMP.S || echo "restore of FPCMP.S fails" sed 's/^X//' << 'SHAR_EOF' > FPDIV.S && X* FPDIV.S -- floating point divide X* Copyright = David Brooks, 1989 All Rights Reserved X* X* This version works by a normal bitwise shift/subtract loop, with separate X* handling of the exponent and a final normalization. 26 bits are computed, X* to allow one normalization and one rounding step. A certain amount of X* black magic and handwaving are involved, but please note that at no time X* do any bits leave the confines of the computer. X* X* Round-to-even is used for the ambiguous rounding case. X* X* float fpdiv(num, denom); (_fpdiv for explicit call; fpdiv for compiled /) X X .globl fpdiv X .globl _fpdiv X Xfpdiv: X_fpdiv: X move.l d3,a1 * We don't need no wimpy stack frame X moveq.l #0,d0 X move.l 4(sp),d1 X beq exit * Numerator 0 - all done X move.l 8(sp),d2 X beq div0 * Divide by 0 - overflow X clr.b d1 * Work with mantissas X clr.b d2 X move.l #$2000000,d3 * Position of msb of 26-bit field Xcmpbit: X cmp.l d2,d1 * Compare against new divisor X blo nobit X add.l d3,d0 * Add in this bit X sub.l d2,d1 * and adjust Xnobit: X lsr.l #1,d2 X lsr.l #1,d3 X bne cmpbit * Done 26 bits? X X lsl.l #6,d0 * Reposition X tst.l d1 * If there was a remainder... X beq doexp X addq.l #2,d0 * record a memory of it. The 2 bit X * .won't be lost by either of the X * ..subsequent normalizations Xdoexp: X moveq.l #$7F,d1 * Calculate new exponent X move.l d1,d2 X and.b 7(sp),d1 X and.b 11(sp),d2 X sub.w d2,d1 X add.w #$41,d1 * Adjust X tst.l d0 * Check for already normalized or zero X bmi normok Xnormloop: X subq.w #1,d1 * Do one normalize step (there can't X add.l d0,d0 * .be more) Xnormok: X add.l #$80,d0 * Round up in most cases X bcc round1 X roxr.l #1,d0 * The rounding caused overflow, sigh X addq.w #1,d1 Xround1: X tst.b d0 * See if trailer was exactly 0x80 X bne ckexp X and.w #$FE00,d0 * It was: round to even X Xckexp: * Check exponent for sanity X tst.w d1 X ble underflow X cmp.w #$7F,d1 X bgt overflow Xsetexp: X move.b d1,d0 * Set exponent X X move.b 7(sp),d1 * Get signs X move.b 11(sp),d2 X eor.b d2,d1 * Form new sign X and.b #$80,d1 * Extract it X or.b d1,d0 Xexit: X move.l a1,d3 X rts Xdiv0: Xoverflow: X moveq.l #$FFFFFFFF,d0 X moveq.l #$7F,d1 X bra setexp X Xunderflow: X moveq.l #0,d0 X bra exit X X .end SHAR_EOF chmod 0600 FPDIV.S || echo "restore of FPDIV.S fails" sed 's/^X//' << 'SHAR_EOF' > FPLIB.H && X/* Common definitions for FPLIB */ X/* Copyright = David Brooks, 1989 All Rights Reserved */ X X#ifndef MATH_H X#include <math.h> /* Now they're all defined */ X#endif X X/* Some facts about the representation */ X X#define BIAS 0x40 X#define MANT_BITS 24 X#define EXP_MASK 0x7F X#define HUGE_AS_INT 0xFFFFFF7F X X/* Redefine a 32-bit float number. Can initialize with unsigned long. */ X Xtypedef union { X unsigned long ul; X float f; X char sc[4]; /* Assuming char signed */ X } fstruct; SHAR_EOF chmod 0600 FPLIB.H || echo "restore of FPLIB.H fails" sed 's/^X//' << 'SHAR_EOF' > FPMUL.S && X* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg X* X* Permission is granted to anyone to use this software for any purpose X* on any computer system, and to redistribute it freely, with the X* following restrictions: X* 1) No charge may be made other than reasonable charges for reproduction. X* 2) Modified versions must be clearly marked as such. X* 3) The authors are not responsible for any harmful consequences X* of using this software, even if they result from defects in it. X* X* MODIFICATION: X* X* D.W.Brooks Apr 89 Tightened up some coding, and looked after some X* trailing bits for the sake of textbook rounding. X* X* fpmul X* X .globl _fpmult X .globl _fpmul X .globl fpmul Xfpmul: X_fpmul: X_fpmult: X move.l d3,a0 * save scratch registers X move.l d4,a1 X move.l d5,a2 X move.l 4(sp),d0 X move.l 8(sp),d1 X X move.l #$7F,d2 * Calculate the presumed exponent X move.l d2,d3 X and.w d0,d2 X beq ret * Mult by 0: d0 is correct X and.w d1,d3 X beq ret0 * Mult by 0: set d0 X add.w d3,d2 X sub.w #$40,d2 * Remove the extra bias X X clr.b d0 * Calculate the absolute mantissa product X clr.b d1 X move.w d0,d3 * Get least significant bits of result X mulu.w d1,d3 X swap d3 * d3 range now 0...fe01 X X move.w d0,d4 X move.w d1,d5 X swap d0 X swap d1 X mulu d0,d5 * calculate inner portion X mulu d1,d4 X add.l d3,d4 * no carry since d3 <= fe01 && d4 <= fffe0001 X add.l d4,d5 X bcc nocar1 X move.w d5,d3 * Save trailing bits X move.w #1,d5 X bra t1 Xnocar1: X move.w d5,d3 X clr.w d5 Xt1: X swap d5 X X mulu d1,d0 * calculate most significant part X add.l d5,d0 X bcc nocar2 X roxr.l #1,d0 X addq.w #1,d2 * Normalize down Xnocar2: X bmi norm X add.l d0,d0 * only need at most 1 shift: started norm AB X subq.w #1,d2 Xnorm: X add.l #$80,d0 * Round uppppp.... X bcc nocar3 X roxr.l #1,d0 X addq.w #1,d2 Xnocar3: X tst.b d0 * Check if trailer was exactly 0x80 (now 0x00) X bne rebuild X tst.w d3 * Check back with spare bits X bne rebuild X and.w #$FE00,d0 * Round to even Xrebuild: X tst.w d2 * Reconstruct the number. First test overflow X ble underflow * Could be mult by 0 X cmp.w #$7F,d2 X bgt overflow Xexpsign: X move.b d2,d0 * Stuff exponent in X move.b 7(sp),d1 * Calculate sign X move.b 11(sp),d2 X eor.b d1,d2 X and.b #$80,d2 X or.b d2,d0 Xret: X move.l a2,d5 X move.l a1,d4 X move.l a0,d3 X rts X Xret0: Xunderflow: X move.l #0,d0 * Underflow, return 0 X bra ret X Xoverflow: X move.l #$7F,d2 * Overflow, return +/- huge X move.l #$FFFFFFFF,d0 X bra expsign X X .end SHAR_EOF chmod 0600 FPMUL.S || echo "restore of FPMUL.S fails" sed 's/^X//' << 'SHAR_EOF' > FP_PRT.C && X/* Modified: */ X/* DWB Apr 89 Handle unnormalized numbers */ X/* Fix exponent if .9... overflows */ X X#define MAXEC 40 X Xstatic char *f_buf; Xstatic int f_upper; X Xstatic char ec_buf[MAXEC+10]; Xstatic int ec_sign, ec_exp; X Xfp_print(x, fmtc, prec, ptmp) Xfloat x; Xchar *ptmp; X{ register long lx, m; X register int e; X X/* These routines have trouble with unnormalized numbers. */ X X lx = *(long*)&x; X if ((m = lx & 0xffffff00L) == 0 || (e = lx & 0x7f) == 0) X x = 0.0; X else if (m > 0L) X { do X { if (--e == 0) X { x = 0.0; X goto uflo; X } X m <<= 1; X } while (m > 0L); X *(long*)&x = m | e | (lx & 0x80L); Xuflo: X } X X f_buf = ptmp; X f_upper = 0; X X switch (fmtc) { X case 'E': X f_upper = 1; X case 'e': X e_print(x, prec); X break; X case 'F': X case 'f': X f_print(x, prec); X break; X case 'G': X f_upper = 1; X case 'g': X g_print(x, prec); X break; X } X} X Xstatic Xe_print(x, prec) Xfloat x; X{ X int nsig; X register char *p; X X if (prec < 0) X nsig = 7; X else X nsig = prec+1; X X ec_pr(x, nsig, 0); X X p = f_buf; X if (ec_sign) X *p++ = '-'; X *p++ = ec_buf[0]; X *p++ = '.'; X if (nsig > 1) X strcpy(p, &ec_buf[1]); X p += strlen(p); X *p++ = f_upper ? 'E' : 'e'; X ec_exp--; X if (ec_exp < 0) { X *p++ = '-'; X ec_exp = -ec_exp; X } X if (ec_exp < 10) X *p++ = '0'; X sprintf(p, "%d", ec_exp); X} X Xstatic Xf_print(x, prec) Xfloat x; X{ X int nsig, nz, i; X register char *p; X X if (prec < 0) X nsig = 6; X else X nsig = prec; X X ec_pr(x, -nsig, 0); X X p = f_buf; X if (ec_sign) X *p++ = '-'; X if (ec_exp < 1) { X *p++ = '0'; X } else { X strncpy(p, ec_buf, ec_exp); X p += ec_exp; X } X if (prec != 0 || nsig) X *p++ = '.'; X if (nsig == 0) { X *p = 0; X return; X } X X if (ec_exp < 0) { X nz = -ec_exp; X if (nz > nsig) X nz = nsig; X for (i=0; i<nz; i++) X *p++ = '0'; X nsig -= nz; X if (nsig > 0) { X strncpy(p, ec_buf, nsig); X p += nsig; X } X *p = 0; X } else { X strcpy(p, &ec_buf[ec_exp]); X } X} X Xstatic Xg_print(x, nsig) Xfloat x; X{ X int prec; X X if (nsig < 0) X nsig = 6; X if (nsig < 1) X nsig = 1; X X ec_pr(x, 1, 1); X X if (ec_exp < -3 || ec_exp > nsig) X e_print(x, nsig-1); X else { X prec = nsig - ec_exp; X f_print(x, prec); X } X} X X/* X * given x, ndig X * if ndig is > 0, indicates number of significant digits X * else -ndig is number of digits we want to the right of dec. pt. X * return the following: X * appropriate number of digits of significance in ec_buf X * ec_sign true if x was negative X * ec_exp indicates the decimal point relative to leftmost digit X */ Xstatic Xec_pr(x, ndig, trunc) Xfloat x; X{ X int isneg; X int nhave; X long part; X int exp, newexp; X int ndigcpy = ndig; X float rem; X char tbuf[20]; X X /* ndig must be >= 1 and <= MAXEC */ X if (x < 0.0) { X isneg = 1; X x = -x; X } else X isneg = 0; X X /* get some digits */ X somedig(x, &part, &rem, &exp); X X sprintf(ec_buf, "%ld", part); X nhave = strlen(ec_buf); X exp = nhave + exp; X X if (ndig <= 0) { X ndig = -ndig; X ndig += exp; X } X X if (ndig < 1) X ndig = 1; X else if (ndig > MAXEC) X ndig = MAXEC; X X /* get some more digits */ X while (nhave < ndig+1 && nhave < MAXEC) { X if (rem == 0.0) { X while (nhave < ndig+1) X ec_buf[nhave++] = '0'; X ec_buf[nhave] = 0; X break; X } X X x = rem; X somedig(x, &part, &rem, &newexp); X X sprintf(tbuf, "%ld", part); X newexp = strlen(tbuf) + newexp; X while (newexp++) X ec_buf[nhave++] = '0'; X strcpy(&ec_buf[nhave], tbuf); X nhave = strlen(ec_buf); X } X X if (fround(ndig, trunc)) X { if (ndigcpy <= 0) X strcpy(ec_buf+ndig, "0"); X exp++; X } X X ec_sign = isneg; X ec_exp = exp; X} X Xstatic Xfround(n, trunc) X{ X char *p; X int oflo = 0; X X p = &ec_buf[n]; X if (*p >= '5' && !trunc) { X p--; X while (p >= ec_buf) { X *p += 1; X if (*p < '9') X goto done; X *p = '0'; X p--; X } X ec_buf[0] = '1'; X oflo = 1; X } Xdone: X ec_buf[n] = 0; X return oflo; X} X Xstatic Xsomedig(x, lp, remp, expp) Xfloat x; Xlong *lp; Xfloat *remp; Xint *expp; X{ X int bexp, dexp; X long ipart; X float rem; X X bexp = fgetexp(x); X dexp = 0; X X while (bexp > 31) { X x *= 1E-3; X dexp += 3; X bexp = fgetexp(x); X } X while (bexp < 10) { X x *= 1E3; X dexp -= 3; X if (dexp < -24) { X ipart = 0; X dexp = 0; X rem = 0.0; X goto iszero; X } X bexp = fgetexp(x); X } X fsplit(x, &ipart, &rem); Xiszero: X *lp = ipart; X *remp = rem; X *expp = dexp; X} X Xstatic Xfgetexp(x) Xfloat x; X{ X char *p; X int i; X X p = (char *)&x; X i = p[3] & 0x7f; X i -= 0x40; X return i; X} X Xstatic Xfsplit(x, vp, rp) Xfloat x, *rp; Xlong *vp; X{ X long ival; X float rem; X int bexp, neg; X X ival = *(long *)&x; X neg = ival & 0x80; X ival &= ~0xff; X X bexp = fgetexp(x); X X if (bexp < 1) { X ival = 0; X rem = x; X } else { X ival = (unsigned long)ival >> (32-bexp); X if (neg) X ival = -ival; X rem = x - (float)ival; X } X X *vp = ival; X *rp = rem; X} SHAR_EOF chmod 0600 FP_PRT.C || echo "restore of FP_PRT.C fails" sed 's/^X//' << 'SHAR_EOF' > ITRIG.C && X/* ASIN, ACOS, ATAN, and ATAN2 functions for Sozobon C. */ X/* Copyright = David Brooks, 1989 All Rights Reserved */ X X#include <fplib.h> X#include <errno.h> X X/* ARCTAN: */ X/* */ X/* The method is from Hart et al: "Computer Approximations". It uses a */ X/* divide-and-conquer algorithm. The argument range is divided into */ X/* five using the partition points tan({1,3,5,7}*pi/16), a polynomial */ X/* valid over +/- pi/16 is calculated, and other magic is used to */ X/* reposition the result. Precision is >8 places. */ X Xfloat atan(a) fstruct a; X{ fstruct absval; X register float tx0, tsq, temp; X register int part; X register char sign; X X static float adj[] = {0.0, 0.414213562, 1.0, 2.414213562}; X static float atof[] = {0.0, 0.39269908, 0.78539816, X 1.178097245, 1.57079633}; X X sign = a.sc[3] & 0x80; X a.sc[3] &= 0x7f; /* get fabs(a) */ X tx0 = a.f; X X/* Figure out the partition */ X X part = tx0<0.66817864?(tx0<0.19891237?0:1):(tx0<1.49660576?2: X tx0<5.0273395?3:4); X if (part == 4) X tx0 = -1.0 / tx0; X else if (part != 0) X { temp = adj[part]; X tx0 = (tx0 - temp) / (tx0 * temp + 1.0); X } X X/* Here's the calculation */ X X tsq = tx0 * tx0 + 1.67784279; X a.f = (0.93833093 / tsq + 0.44075154) * tx0 + atof[part]; X X if (a.sc[3] != 0) /* Negate if negative */ X a.sc[3] ^= sign; X return a.f; X} X X/* ARCSIN and ARCCOS use the standard identities. There's some less */ X/* optimal code here becausethe released Sozobon C can't properly */ X/* compare two negative floating numbers. */ X Xfloat asin(a) float a; X{ X if (a > 1.0 || (a+1.0) < 0.0) X { errno = EDOM; X return 0.0; X } X X return atan(a / sqrt(1.0 - a*a)); X} X Xfloat acos(a) float a; X{ float temp; X X if (a > 1.0 || (a+1.0) < 0.0) X { errno = EDOM; X return 0.0; X } X X temp = atan(sqrt(1.0 - a*a) / a); X if (a >= 0.0) X return temp; X else X return M_PI + temp; X} X X/* ATAN2: */ X/* */ X/* Computes atan(quotient), and returns that for positive cos, else */ X/* extends the range depending on the sin. */ X Xfloat atan2(s, c) fstruct s, c; X{ register float r; X X if (c.sc[3] == 0) /* Infinite argument */ X return (s.sc[3]<0)?-M_PI_2:M_PI_2; X X r = atan(s.f / c.f); X X if (c.sc[3] >= 0) X return r; /* Range -pi/2..pi/2 */ X if (s.sc[3] >= 0) X return M_PI + r; X return -M_PI + r; X} SHAR_EOF chmod 0600 ITRIG.C || echo "restore of ITRIG.C fails" sed 's/^X//' << 'SHAR_EOF' > LIBM.uue && Xtable X !"#$%&'()*+,-./0123456789:;<=>? X@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ Xbegin 644 LIBM.ARC XM&@A,24)-+D$ \@ "&H@ $R0 ,,2Z6"H!:94 ,_\K0D9/FC(LW !( " !@z XM0$( D P$L 4 &* ,!HJ"@ (@--$!4XL?(/'I)S& ! < %@ 1) P/@ )0Ry XM%\L%#%AB:=E&P@Q^_X!!) ' )-O # X\>*DS@L>HO(! O*")0(GN89">=("x XMR#]^3P%5#%+U*U:M3[X$$R8SP)F*S.P * O6A=FLD AL[?J/WM-D#[*1Y5&Jw XM2S9@3T?-H-7C::8,?'(]]53"$HVR],[FW?H"@&:]3SIC_LS9,U[0HNUF/EV:v XM=.BYJEUWE@W[+EJ^\)38G7<& XP!,0$(.&, $M _^8I(4!<P?'D(.S" P/ u XMGS^ZGTT8'_09"U>O^$ YP5Q@%L48<?2+8N/MFN^_*C[<\<>.^LG8,R-K/ATt XM:%4 5]UWQ5IMG:$ "#R(!4 02S7U'P)_!<;@?9V%49T-8(BS'VP 1B@8;1;Zs XM@X$+@#P8H@,D?M9@'5_,D88;0XD"40%?C/'&'#&6%P C7] 1!HQYR0B)><Y\r XM488<<KB!$ "(S&@&'&W4P49Y34)2P)-CM%'4D%5>"4<89)!!Y8Q?/&D&'6],q XMV669<+"!IAE,.@G'''6(,::53Y*1AEQ<0F3 >4!.J2@ P!*J*&!SHCHD 4 p XMP $ BQ8*Z:2-#IIHHR1,>B@ E4IJ::,L:#JII99N^BD F48*:*>K7NKJJ:1*o XMBJFHK=) JZNIBMJHK8AN.FNOG + JZBGYHKHKK<62ZRGDJHZ:@' 6FDJLZWRn XM<&NC1"Q[;**MQNJK4=<*JVVBW@;+1+*RDIMNJ-$V&VRIHZ9[ZKGM.@MKNO2.m XM.^VV5&B:QD %'5010PXI%-%$%2&@0$4:532 (>5E"LD!($$B$DDFH:3232\%l XM1Y-P+/W14@LP(O //D^MTL O5-G5WGU=$+C06P' \-0RK[#B WNNQ<S6S LQk XM (&U +QD P"VR$0 G " 4E^"%07S'GA/63,,(V2YS#.%IMWF%3V_E0,$$L! j XM0]Z0$(! %01/AZ-*"S]@]A0\-LP!A'M<X^TU@+JU= 8!-K44'8!');6B$D.\i XM]0\=88]=]MD$J-T"%"6EMV!9\&R-UFQ<8Z[Y9J]-?3)U_W@P]$+R^<7#+Y h XM8$S6)_<LLUL(G"Z ?-(\!<HW]PSQ.6@^%UB[M0/(!\OI!,B'RH:69PV@:U[,g XM;H8*_>75_(-Z@Q[\S [\] \G0Q6UXH/8=P[U@MD30&+YFP-@83^Z@.'+2%]=f XM;Q7TTE-OK?7G.Q]@^[+[F5NZ!Q3PY45\3'&*5<AW/_,I:$( /$V*N/8^$\#'e XM!9!C'^BX,#OB1.<K8.!$A+0A!/L,!0R*H!\_^O8 ,V"@;PM@PX%X )AL2"V!d XM"*IA$,#@%Y8P0(.H<1\ ^($+[\"'A6TPP ?CPPP8]F2$);0+/SX#!EJ,4!@Fc XMS L8A$0 :DP@&3]XH"8$D0<A# 4PU_@!8+ !!$LL8QQ!T.$7PN C( U 2#0*b XM@XOL*"3SV&*.-L+1D/HH "7,L8XRJ$@?!R !+&GI3E[2$Y\&T*4G16E*?<+3a XME\($R2?1R4Z9I-&1DK2D-<TA#G*@PYW^I*Y-N5)1L&05KM#UK7+]:ESELA>Uz XMWK6N<<G2EN("5J.LY2QA+H26O*QE+XU)3%T%TYG-W%>\I%FO<#'$6;_<);*8y XMB<Q39<N8[)IF*U^E350A4YK9;)6QQ"G-<MWK6^M\I2S3&:QH4LJ<U214H_)5x XMS5,-:UO>#%>_L F <!:3G/ \9S(7>BI[JE.AC (7L-J9KG_>,Z#&'.@]#2K.w XM=\XRG]QB:+KLF<N0RA*@[@(F1U]94GC!BY[#="8PF]FIFI;'IA'-Z0!L"H!3v XMIE)@"B'80PZ&$0$<+2,;&9(Z(+( (X1$A2\8 S-@("BF. #*UI)2XP& ,2Qu XM@0'>,R!1,B(.2\@$"+\)CELJ@HH.R.0'+9&"[WA B%^P(VX\, 0J0C&84- #t XM'[\ 8FLZU\ (>JU^4A3L:[((&OA,P2[_6$]A09<:VX ./K\1!Q*F (1H0':)s XMI(.!6P$ A):03@LM0J4J!TFF42JI(I6$DI0ZN4DQA3)/>UHE2]TUT9"VJU$,r XM@.@NI751>1GW6Q0(UZ.JV:CD&G.Y'2UG/%T%78HFE+F.TA<NAPNMBL#A#7<0q XMV$.$:C")8"0 Z&!84@?@"J9NZ6)?.4E*A$"$J;Z0)0]P@T\*&#ZC($4I"80Ap XM&Z(( 9DQSCM_>$ /C-!M%BA@P@(ZU#$ XRSF0<'( . R!;PGQ].5GV 2)\1o XMO;)"(IR! ;KYQS^(8YR9J!BT %C<%[Y[AQQ9R4A(>FV<;FPF-*F)3$]RTQO@n XM%-LL;8F29&+#&]Z2E]A>$I)&PL.6"% E5K8TI5@&KG9WVRKGLC-8U0W6=%VZm XMTP++-*7=5:DS+5JM+8>4N)8"0!FD+-Z@-F2HYJU( 4*%5(Y (&(0.0 JGDH2l XML S@*>T%@!$4&ST!GH$"WA-*7D"0@Z%<=7S[(P"B*[+H#P\6+=MSRUC!P(RGk XMX$(5.R""8KO2H0][YVA>%< 4?&<5) PCJ@P.\7U8#:'^/246<NA"+YY2#V;Tj XM =/:<<;MC +Q7*N?<[N&F4Y]+]IBXX?OS%'9R&;5ID<0&QD,UMY(K<VQFY%i XM/OJ JE5"!(P+\D)!+:M?_VAC[M"=9D7J!E"(_.!N>*]GWH2U;!!5E,!\(R!$h XM/+B@*Q K\+V0V'X-7ZROI9B^%?UC2']XX"(J$8P@8.(&[PA"*?QAC2#4@@#Rg XM"$(QSH""(%R#"/L(@CJ \;HH3QF/+7H1&LK3QP#8H$8WVCEKAQ0 //3H1T*_f XMHXYTX<@CK\FUI903F&R+9$T^.91L.E.:=DRC(+^)ZYZL$VTEJ5N3CO.6!XUHe XM.!MUS7!YU)_A&C-OB_LMDI;SF[<Z:*OX&2R-*K-;QQ5IFXW)9E<Y-%B%;VBXd XM+ HO+CNS[02UNW412OE&<0&9C?+[/0_OSG("\U27QV[A8]K/X9I^\.*$Z3-1c XM^BW-MRKTQ<5IF74J>YXJV2!+LG/!_(2PAHA#O0,#Q;@#[0="]Z5ZFO9T6CJXb XMW^]-N-)YP?3)4Z[84+\% -AXRLGAT;+GW:?1!:H(+UH@D[P<_WPEG+CW#UN7a XMB/,%95JC^*X?GECY'Q9E4!M ^E6QB6U0A0?4( D?$#<NDSZE\3N?-FWU5EFKz XM<4(Q]D,\ &P5\ -:Y1* , Y T#HR$0AD\VQYT6"7]36C55H<Q@/;UWW5UEA4y XM8X($P'VK1F*DPP',PP/>L 750(#Z5AUN (($8'%Y\06W9V,T<GLQ .*I"."x XMT'10!G6P)2>?1%M3-W:Y=5NRA4E5UW5M\G55]G>NXF5I5V;0Q79N5TY>&%V w XMAUS=)"_=-4]GAT]F&"P<U7FULEUUYTN5UX:'!RJ8!P!Y6%![R'G+1'F-YUO!v XM@G>H9RIKV(9Q&'C*HDM<6%*D=T\ 8 9M\ 9D %3'M'M$Y3"R 'P+47R0L 5u XM U_\4($=(Q-_ LR@05O@ "#<Q4)Q$#K]X&Z-A0*%W$/YF@:X$04 '%3=!KPt XM 5JNH$*F"!.HJ(H P(JN>#^QN$ ?QH.W^(L.UD&[>!-LT(L3)W#!*$5@,(R%s XM5HS!D8JK^ 8>\(H@ ",, * <(X%]@)L\V'C\XRUF!?> 0;00#_PUX[*!Q\Kr XMH6*GJ&'(R(H&@$ .8G]Y\7XND&"_PX,'^&%@@ PU4@9I8(4X9P9*]@9R<(1Yq XMH09?4(ED "=#UT5EXI$\IR,<D'4^QG5L(F1$)B=&!H6<1(5/2(5D1X575W56p XMMDO41(C M$YZB$ZK]V4OA8=ON)-75GH/M2WA!$R)AV6LYRIX=Y1OII/CY'C8o XMLH<^Z8=(Z2I\)Y6#2%"Y(H=PZ$RN!Y608@9A( 9S@(GDQ7OG10O -R2PP%08n XM9C$;\HH5=G$#\ ?X9@7\,0#@B(ID(P,^A 3! V!H!U*, AN4%4 <&D)9 L6m XM]@=O8 &1-B,+AW$ \HI@P V!.1-D PB#T $DR)G$L"%3Y0#LR !" 6OF%4<l XM8XP:IH&DM9HP B?"0B <%:D:5K04"9I*4A*=V-L0 9S5A0 P$424"9R<)P:k XM210X1DI-&!% .8AD]H6]E9UT%R^-$H:P=)U?9I14"9[86953N2]T-&1L>6?Ej XMA3!#@@MQ.0 L,20$$&AU28I(X ;RYA\?MD1]61$$UQ0E<'V'-&0E>6,M,@8_i XM0@9UP$4@T")SH*!NT)((&J$_0J$Y^2UM=RI>9IWI$F8'1!!N0 =F(#"E8!%5h XMD"V;" &X 6>* #PP%2@!%^R<!(>P $F ",0@ (P0@'TI003\!8"P ,,, $ g XM4 ),HPI"4 1"X#*C!0+_D \]P =ZJ0]"H)_\,*5ZZ0^CI0#_< ]+X [_< M"f XM8 1", 12L A% 0$3(&Z3!@1" 00 '!,1PX$*=L2ILP( /6H@##, S2 0Ve XM$ !*@*7$T0-#\ _^ ;*@#AF $Y 0!0F@]4-5HP$*55A*C_H ]@ MX.@'(d XMR -N@HP < 9J@(P@< 9$@(PJ< 9&@(PK< 8X@(PM< 8J@(PN< 8:L)H/PJ8Oc XM 5=.T#I<\ 120 1I2CHR,*4+ 4(QY@4Z8"T!0#I6T %3,#HQY@0VP &%^A5Gb XM@ ":NJ@QY@.:RJDQ9@-3L B=BHQ>,"5(@XQ%<'V$@(Q'< 9\$)!F0 FC!0%?a XMVH_W\*MST0!*8 1GP 4@T(O21@#>P \ H !^S=)P X64:0 @ =F\$,-\ (-z XMX!H_8!?^L+&;VH_YX*_]B _^^@,%@+$=!D0)"P 6P$:DHP-% 0,< :@T )4y XM\ ^R\+ 6@;$>ZP^^"@AP51:R\!DKRP!:.B2+R@G(* 9M4!WN@(QX "/^8 ZTx XM*09D4P[KN <(T(/0P!&6P!'(P!%BLA"J,#!E2[8< ;'",;8"H+9MRQ&7)QQNw XMZ[;")QQG^[9RRQ'DD+8<00Q\F[<+00/RP0@P0 !'@0-XL"(\ *W4T0_F\ -]v XMBK$-*P(%ZX$(J[ ,*[ (H+/)4QWJH+.W4QWB ,40#9@H VC)0!?*A^<,%HFu XM<P_R(0F+NQ"6&J7*:@";JJPF Z[^( ?R00<@P 14P @:,&@!$ 3ML!!" %-t XM>C)/BJG5X0@J0 6<"P;JT+C:\ 4S)J(DBG,U0@=Y =EH))2@B86HI)S,!!Ls XM< <9N2;;2Z+%N29/LKTOLB9"9B&9E*'CY*'B*2AIEF:>\K^OU%M:UEM?:9[Er XM&2W=Y;]Z)Y1.Z< )C,!YUU$ /'GDN;]4:<'CB68#/,%=%IX2W"H@>GINYHABq XM!L%IV,#?LI0!;,)B25 =T2@Q+!S!,L,V7,,X+,,Y3,,ZW,,\_,,W[,-!#,0Xp XM['@N/'>$!\)B><!PUL+[*\#?F<'F22H5_&4]):$EBA"$<*($D*)N61$28"M]o XM!B#S.0"8$&B,8'Q(<!(?@*,EPZ, X*-'H 048 8*$*>'VQXXA(XOL #!FHQ/n XM@&%*0 1+(@Y7JJ@,D%Q(NA#&(!?/JF+*&@ GHZQ>:J5&$,F*BLGV<+0# !;[m XM,P"MDY__( >RD6FB' :N$000&P!" P J8,>'[ ^'; ]2P BUO*84X*;DAJ=Tl XM*A/# 0*Z0*7_8 8"L*1X2@%ZRJ<+.PS%$*@Z$ ]4 2C@PQ38,N,@,NZK#:\k XM'!S,$33'K "E!0*AR@9F0*H#RZIGH 3'C M < 8B,,A?I01'0%4PP ,J)A_Aj XMH:-]_ ,]**Q/ ,'(!_FP*M^W#K>(<CZZ0]_@P7MA0&U3,=PX@_<(#^Q/,NDi XM@P?5# :F@(Q;T :@ +5NH FTN057F[5;ZP1="RE.D# JP-(N#2 M#=,OK3X5h XM80!G;!'G8A$[H=,500 [+0!0P!'](M-$+0!(\-(($-,$@&%$G=0O?0 *2]0$g XM,-1.+=5"0#I(<,SXC,V0H\URVLLJ\1;^( ](0 P(,A300 A>/:?! 0&*DS9\f XM7-" C&&XT!9L8 WRP0RS&ZW5@0CR00B'K ]E?=9YD=9K#=8 0]E?=9YD=9Ke XM#=80SE@ X08 @Q<+G$ "@.4)#@"X^ (P 8;& #^%L(! ($"-%X (!$ 40(d XM$ @0@$DD<(8 #QX3E;CYI\_,1"T])"J@*60FOX@ 2M@,P" G $T"1I$J)"Ac XM0X@2 [3!*"2(NW]A8+B@B018-&!"(" A!@*F2&B$2)I$J1( @C, !B#04 !b XM$ @?@! ,C.,DUPA"7!YH@*($B)G$.SB%]B, 25%;/:CMSCP&30P"DPIH@3(a XM&3"'SW#1RA78"P O!OP-#.6)5:PB&DA"!"V0";P%#R9<V/#AV+*!T:H]F5+Bz XM6PQT[>+5RQ?K:I&#"X.A1!>,.IG__,'MITHI!A50&!0,\(^?8Q #B "ZK<1(y XM8A6#I!RYV$^1CD%@[%4'\,\'4!AFV*"4;DWU!M5$;=@"%!YG4 4%F<X8!0"x SHAR_EOF echo "End of part 1, continue with part 2" echo "2" > s2_seq_.tmp exit 0