Path: tut!draken!kth!mcvax!uunet!ginosko!rex!ames!mailrus!iuvax!pur-ee!ea.ecn.purdue.edu!housel
From: housel@en.ecn.purdue.edu (Peter S. Housel)
Newsgroups: comp.os.minix
Subject: Floating Point for Minix-PC, Part 01/03
Message-ID: <13808@ea.ecn.purdue.edu>
Date: 28 Jul 89 21:09:53 GMT
Sender: housel@ea.ecn.purdue.edu
Reply-To: housel@en.ecn.purdue.edu (Peter S. Housel)
Organization: Purdue University Engineering Computer Network
Lines: 1704
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of archive 1 (of 3)."
# Contents: README MANIFEST NOTES cfu.x mlf8.x vfprintf.c
# Wrapped by housel@en.ecn.purdue.edu on Fri Jul 28 13:35:03 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1463 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis package contains a floating-point arithmetic package for Minix-PC
Xversion 1.3, and a few ``mostly ANSI-compatible'' additions to the C
Xlibrary. Installation instructions are in the file INSTALL, and notes
Xon implementation are in the file NOTES.
X
XThis is more-or-less a medium quality implementation of floating point
Xarithmetic for the Minix C compiler. No 80x87 math coprocessor is
Xrequired (or even useful) to use this package. The binary format
Xshould be identical to that of most IEEE 754 implementations, and many
Xoperations give bit-for-bit identical results. It is by no means,
Xhowever, fully standard-conforming. (There is no support for
Xinfinities, NaN's, or denormalized numbers, for example.)
X
XWhenever compiling a program which uses floating-point constants,
Xand/or when linking any program which uses floating-point arithmetic,
Xthe "-f" option of the C compiler should be used. (This causes the
Xfloating point constant postprocessor to be run, and adds the floating
Xpoint library to the list of libraries linked with the program.)
X
XAlthough the goal is to eventually provide all of the math functions
Xmentioned in the math.h file (and in section B4 of K&R2), not all of
Xthese are available yet. (Due to portability problems, the BSD 4.3
Xfreely-redistributable portions of libm are not yet usable.)
X
XAny bug reports, suggestions, questions, or improved code would be
Xappreciated.
X
X-Peter S. Housel- housel@ecn.purdue.edu ...!pur-ee!housel
END_OF_FILE
if test 1463 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1756 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X File Name Archive # Description
X----------------------------------------------------------
X README 1
X MANIFEST 1 This shipping list
X CRCLIST 3
X INSTALL 3
X Makefile 2
X NOTES 1
X PATCHDATES 3
X _mult.c 3
X _poly.c 3
X addsub.x 2
X atof.c 3
X cc.c.cdif 2
X ceil.c 3
X cff.x 2
X cfi.x 2
X cfu.x 1
X cif.x 2
X cmf8.x 3
X cuf.x 2
X dvf8.x 2
X exp.c 2
X fabs.c 3
X fat.x 3
X float.h 2
X floor.c 3
X fpp.c 2
X fprintf.c 3
X frexp.x 3
X ldexp.x 3
X log.c 3
X log10.c 3
X math.h 3
X mlf8.x 1
X modf.x 2
X ngf8.x 3
X norm4.x 2
X norm8.x 2
X pow.c 3
X printf.c 3
X ret8.x 3
X return.x 3
X sprintf.c 3
X sqrt.c 3
X stdarg.h 3
X stddef.h 3
X strtod.c 2
X strtod_aux.x 2
X trp.x 2
X vfprintf.c 1
X vprintf.c 3
X vsprintf.c 3
X zrf4.x 3
X zrf8.x 3
END_OF_FILE
if test 1756 -ne `wc -c <'MANIFEST'`; then
echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'NOTES' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'NOTES'\"
else
echo shar: Extracting \"'NOTES'\" \(23050 characters\)
sed "s/^X//" >'NOTES' <<'END_OF_FILE'
XHere are some notes on the implementation of the PC-Minix floating
Xpoint routines, and a (rather extensive) list of bibliographical
Xreferences on floating point arithmetic.
X
X1. IMPLEMENTATION
X
X1.1 A Brief Overview of Floating-Point Math
X
XSeveral of the references have better explanations of what floating
Xpoint numbers are and how arithmetic works on them. The Sterbenz book
Xgives a fairly rigorous mathematical treatment; the first of the
XPlaugher references provides an excellent in-depth explanation from the
Xuser's point of view. Briefly, my attempt:
X
XMost of the computations done by computers are done on integers. These
Xare simply represented - each bit of a binary quantity is used to
Xrepresent a power of two. The least significant bit represents the
Xnumber 1; the next, the number 2; and so on.
X
XFloating-point numbers are often referred to as "reals". This is a
Xmisnomer; the number of distinct values that a 32-bit floating-point
Xnumber can take on is the same as, or even less than, the number of
Xdistinct 32-bit integers. However, floats can represent a much larger
Xrange of values. As an example, 32-bit binary integers can range from
X-2^31 to 2^31. A common format for 32-bit floats can have magnitudes from
X2^-127 to 2^128.
X
XThis is accomplished by splitting up the bits of the binary quantity
Xinto three fields: a sign, a biased exponent, and a significand
X(commonly called the mantissa). The significand represents a number
Xbetween zero and one, and is usually normalized so that it ranges from
X1/2 to one. The number represented is then:
X (sign) mantissa * 2^exponent
X
XThe exponent is stored in the bit field with a bias added. The bias is
Xgreater than or equal to the minimum actual exponent, so that the
Xbiased exponent is always an unsigned quantity, and no exponent sign
Xbit is required.
X
XZero is usually represented by a zero biased exponent and a zero
Xmantissa. This allows a floating point zero to be represented by an
X"all-zeroes" binary number.
X
X1.2 IEEE Standard Number Representation
X
XThe IEEE (Institute of Electrical and Electronics Engineers) Standards
XCommittee has defined a standard behaviour for floating point
Xarithmetic implementations. This standard, IEEE 754-1985, defines the
Xformats, operations, conversions, and exceptions supported by a
Xconforming implementation. Four formats are defined: single precision,
Xsingle extended, double precision, and double extended. Field widths
Xand interpretations are defined for the non-extended formats as follows:
X
X Single Double
XMantissa bits 24 53
XExponent max +127 +1023
XExponent min -126 -1022
XExponent width +127 +1023
XExponent width in bits 8 11
XFormat width in bits 32 64
X
X(The IEEE standard numbers the bias and exponent differently from a lot
Xof other floating point literature, including the ANSI float.h and the
Xsource code of this package.)
X
XIn addition, representations are defined for positive and negative
Xinfinity. There are also quantities called NaN's, for Not a Number.
XThese result from illegal operations, and can either cause an exception
Xor propagate as operations are performed on them.
X
XThe standard defines several arithmetic operations: add, subtract,
Xmultiply, divide, remainder, square root, and format conversion. The
Xbehaviour of each these operations when given a number, infinity, or
XNaN is detailed. Rounding modes and exceptions are also defined.
XNumbers can gracefully underflow as "denormalized" numbers with a zero
Xbiased-exponent.
X
XMany of these features are nontrivial or slow to implement in software.
XFor this reason, this implementation does not strictly conform to the
Xstandard. The number of bits for single and double precision, the
Xbitfield layout, and the exponent bias are the same. However,
Xinfinities, NaN's, and denormalized numbers are not recognized. There
Xis only one rounding mode, round-to-nearest with round-to-even in the
Xtie case.
X
X(A newer standard, IEEE 854-1987, is similar to 754-1985 but is more
Xgeneral. For example, numbers may be represented either in binary or
Xdecimal, and the formats are not specified exactly.)
X
X1.3 Floating-Point Math in C
X
XThe C language defines three floating point sizes: float, double, and
Xlong double. (long double is new with the draft ANSI C standard, and
Xis not available in the Minix C compilers.) The standard states that
Xprecision(float) <= precision(double) <= precision(long double), but
Xthat they may have the same representation.
X
XThe primary floating point datatype in C is double. In K&R C
X(including the Minix compiler), all floating point quantities are
Xextended to double before doing arithmetic on them. This is part of
Xthe "usual arithmetic conversions." (ANSI Standard C will relax this,
Xso that expressions containing strictly floats may be done using
Xfloat-arithmetic, provided the result is the same "as if" doubles had
Xbeen used.) Floating point arguments to functions are also widened to
Xdouble, except in Standard C when an in-scope prototype says that the
Xfunction takes a float argument. All of the standard library functions
Xreturn doubles.
X
X1.4 The ACK routines
X
XThe Minix C (and Pascal) compilers are based on the Amsterdam Compiler
XKit, or ACK. The compiler generates 8086/8088 assembly code files from
XC program text using several passes (each found in /lib or /usr/lib) as
Xfollows:
X
X file.c file.k file.m
X--------> cpp --------> cem --------> opt --------> cg --------> file.s
X
X(The "-v" option of the "cc" command allows the invocation of each of
Xthese passes to be seen.)
X
XThe "cpp" program is a version of the usual C macro preprocessor, which
Xdoes "#-command" processing and macro substitution on the C source
Xcode.
X
XThe ACK compiler "frontends" take as input a program in the source
Xlanguage (in the case of "cem", C) and generate EM machine code. The
XEM ("Encoding Machine") machine (which does not exist in hardware, but
Xwas defined as a generic machine for the ACK system to generate code
Xfor) is a byte-addressable, stack-oriented processor. It supports
Xoperations on integers (signed and unsigned), pointers, sets, and
Xfloating-point numbers. Each data type is available in one or more
Xsizes, which are identified by their lengths in bytes. The
Xarchitecture was designed based on research on instructions used by
Xblock-structured high-level languages.
X
XThe output of "cem" is in EM compact assembly format. This is EM
Xassembly-language represented in a compact byte-code representation.
XThe definition of this format, as well as the format of the ASCII
Xassembly language and the object code format, is described in a
Xdocument included with the ACK system. An excerpt of this document was
Xposted to comp.os.minix as articles <1650@ast.cs.vu.nl> and
X<1651@ast.cs.vu.nl>.
X
XThe "opt" program takes the "cem" output and performs some
Xmachine-independent peephole optimizations on the EM code. There are
Xas many as 400 EM instruction sequences which the optimizer can
Xtransform into more efficient ones. This take the pressure of
Xgenerating optimal code off of the frontend and reduces code
Xduplication between frontends.
X
XThe ACK system also includes a global optimizer, which is capable of
Xmany more powerful optimizations. This program is, however, too big to
Xrun under Minix and is not included or available.
X
XThe code generator, "cg", reads the output of "opt" and translates the
XEM assembly into code for the target machine. For Minix-PC, this is
X8086 assembly language in the Minix compressed-assembly format. Most
XEM instructions translate into a small number of 8086 instructions.
XHowever, there are several which would translate to a larger number,
Xperhaps six or more. These are broken out into subroutines.
X
XThese auxiliary subroutines are found "near the end" of the C library,
Xand do such things as implement switch-statement jumptables, convert
Xbetween various sizes of integers, do 32-bit arithmetic, and so on.
X
XOne of the files in this set of auxiliary routines is called "fakfp.s,"
Xfor "fake floating point." The "cg" program is capable of generating
Xcalls to a set of auxiliary routines which implement floating-point
Xarithmetic, but no real routines are included. Instead, fakfp.s
Xincludes a stub-routine which generates an EM "Illegal EM instruction"
Xtrap and aborts the program.
X
XThis package includes many of the omitted routines. There are stubs in
Xfakfp.s for the following:
X
X.mlf .mlf4 .mlf8 multiply
X.dvf .dvf4 .dvf8 divide
X.ngf .ngf4 .ngf8 negate
X.adf .adf4 .adf8 add
X.sbf .sbf4 .sbf8 subtract
X.cmf .cmf4 .cmf8 compare
X.zrf .zrf4 .zrf8 zero
X.fif .fif4 .fif8 split into exponent and fraction part
X.fef .fef4 .fef8 multiply and split integer and fraction part
X.cif convert integer to float
X.cfi convert float to integer
X.cuf convert unsigned to float
X.cfu convert float to unsigned
X.cff convert float to float (float <==> double)
X
XBecause of the "usual conversions" rules for expressions in pre-ANSI C,
Xall arithmetic is done in "double" floating point, even when all of the
Xelements are of type "float". This makes it unnecessary to include
Xmost of the auxiliary routines for doing arithmetic on float-sized
Xquantities. (The exceptions to this are the conversion routines, which
Xconvert between all different sizes of floating point and integer numbers.)
XThe "C" compiler does not generate FEF or FIF instructions either, so
Xthese are also not implemented.
X
X1.5 Implementation notes on the ACK routines
X
XAll of the routines named above expect their arguments on the stack,
Xand return their results there. This, and the use of the normalization
Xsubroutines, determine most of the structure of the routines.
X
XMost of the floating point ACK-auxiliary routines call .norm8 or .norm4,
Xwhich take a denormalized mantissa, an exponent, and a sign, and pack
Xthem into a standard-format normalized number. (Note that these are
Xnot actually EM instructions.)
X
XWhen calling .norm8 (.norm4), there should be a 64-bit (32-bit)
Xmantissa on the stack. The radix point is assumed to be in front of
Xbit 52 (bit 23). The bx register should contain a properly biased
Xexponent. The high bit of dh is 1 for negative numbers and 0 for
Xpositive numbers. The dl register should contain eight bits of information
Xto be used for rounding.
X
XMost of the work of normalization involves shifting the mantissa up or
Xdown until there is a 1-bit in the position where the implied 1-bit
Xwould be, and packing the exponent and sign into the number. When bits
Xare lost (by shifting off of the lower end), it is necessary to round
Xthe number to minimize the error introduced. (Simply truncating those
Xbits which are lost, known as "chopping", has a high average error and
Xa high error bias.) Round-to-nearest is used, and tie cases round to
Xeven (lowest bit is jammed to zero). When 1-bits are shifted out of the
Xeight-bit rounding register, its least significant bit "sticks" to 1,
Xto allow those bits to participate in the rounding process. (Only three
Xbits, usually one each of "guard," "round," and "sticky," are necessary
Xfor this type of rounding. However, coding for a three-bit register
Xwould be larger and slower when there are already instructions for
Xmanipulating eight-bit registers.) Overflows cause EM traps, and
Xunderflows return a zero.
X
XThe .zrf4 and .zrf8 routines simply push a zero of the appropriate
Xsize. The .ngf8 routine flips the sign bit of its argument.
X
XMost of the rest of the routines have a couple of code segments in
Xcommon which set the si and/or di registers to point to the
Xarguments or result, and which unpack a number into its
Xsign/exponent/mantissa components.
X
XThe addition and subtraction routines, .adf8 and .sbf8, are the most
Xdifficult. The algorithm used is described in pseudocode in Rick
XGrehan's "Floating Point without a Coprocessor" (see the references).
XBasically the scheme is to line up the radix points of the two numbers
Xand add or subtract them depending on their relative magnitudes. Most
Xof the problems are caused by the scarcity and small size of the
Xregisters in the 8086.
X
XMultiplication (mlf8.x) consists, basically, of adding the exponents
X(being careful with the bias), exclusive-or-ing the signs, and
Xmultiplying the mantissas. In order to take advantage of the 8086 MUL
Xinstruction, Algorithm M from section 4.3.1 of Knuth's Seminumerical
XAlgorithms (again, see the references) is used. The loop is unrolled
Xand some special cases are commented out or otherwise avoided. (No
Xdoubt a faster multiply would have been possible using the algorithms
Xin section 4.3.3, but that would have required much more study than I
Xwas willing to do, as well as requiring anyone else who maintained the
Xcode to understand it. The method used is reasonably fast and
Xreasonably straightforward.) A 106-bit mantissa is generated; the most
Xsignificant of these are used for the answer and the rest are packed
Xinto a rounding byte.
X
XDivision (dvf8.x) is like multiplication except that the exponents are
Xsubtracted and the mantissas are divided. Again, see the Grehan
Xarticle for the pseudocode. Division by zero causes an EM trap.
X
XThe convert-float-to-float instructions (cff.x) convert either an
Xeight-byte float into a four-byte float, or vice versa. This basically
Xinvolves unpacking the number, realigning the mantissas, and adjusting
Xthe bias. The normalization routines are used to re-pack the result.
X
XConverting a floating point number into an integer (cfi.x) or an
Xunsigned integer (cfu.x) involves realigning the mantissa until
Xthe radix point is at a known point, and taking everything before
Xthat point as the integer.
X
XThe inverse operations, in cif.x and cfi.x, are implemented by placing
Xthe integers into a mantissa field, placing the radix point at the
Xend, and normalizing.
X
XThe floating-point comparison routine, in cmf8.x, uses a quick
Xalgorithm outlined by Plaugher in the "Safe Math" article. It takes
Xadvantage of the way floating point numbers are packed into memory, in
Xthat larger floating point numbers, when taken as integers, compare as
Xgreater than smaller ones. The main point of difficulty is that
Xfloating point numbers use sign-magnitude representation, so they must
Xbe converted to pseudo-2's-complement before the comparison. The
Xreturn value is a 16-bit integer on the stack. If it is less than
Xzero, the first argument was less than the second; if zero, they
Xcompared equal; if greater than zero, the first was greater than the
Xsecond.
X
XWhen an EM instruction is supposed to indicate failure, the auxiliary
Xroutine will usually call the EM trap routines. A "trp.x" file is
Xalready included with the library, but the one presented here provides
Xmessages for more trap codes. All of the codes are defined in the EM
Xdefinition documents.
X
X(In general, in all of these routines, watch out for the bits whizzing
Xthis way and that. Be especially careful of the ones that fall off of
Xthe ends.)
X
X1.6 Assorted other library routines and their implementation
X
XThe above routines are all called implicitly by C code. Most C
Xlibraries also provide several explicitly-callable subroutines that do
Xfloating-point math.
X
XThe ldexp() and frexp() routines are implemented in assembly code.
Xfrexp() is basically a frontend for the number-unpacking routines,
Xand ldexp() is a frontend for the normalization routine's repacking
Xfunction. The ldexp() function is careful to keep the exponent within
Xthe legal range, and returns HUGE_VAL (defined in ) of the proper
Xsign when it is not.
X
XThe modf() function is also written in assembly. It unpacks an
Xarbitrary floating-point number into two floating-point point components,
Xan integer and a fractional part. Numbers which are large enough or small
Xenough to be entirely one or the other are special cases. Otherwise,
Xthe number is shifted until the radix point lines up with the end of
Xthe integer part, the result is split into two parts and each half is
Xrenormalized.
X
XThe Standard C routines used to convert human-readable forms of
Xfloating point numbers into their internal representations are atof()
Xand strtod(). They are mostly the same, except that strtod() can store
Xa pointer to the end of the number being converted. Therefore, atof()
Xis defined in terms of strtod().
X
XPart of strtod() is in C, although the entire subroutine was translated
Xfrom VAX/11 assembly (the freely-redistributable 4.3BSD-Tahoe version
Xof atof(), which is not included here). The C portion uses _mul10add()
X(written in assembly, and included in strtod_aux.x) to accumulate
Xdigits in a 64-bit accumulator until it overflows. Then the optional
Xexponent is parsed, the base-10 exponent is computed, and _adjust()
X(also in strtod_aux.x) is called to multiply the 64-bit integer by
X10^decexp, and pack the result into a double-format floating point
Xnumber. All sorts of clever tricks are used in _adjust() to maximize
Xspeed and precision; credit for these goes to the author of atof.s.
X
XStandard C defines vfprintf() as a for producing formatted output from
Xa variable-length vector of arguments. The version included here is
Xa very slight modification of 4.3BSD-Tahoe's _doprnt() code (which
Xis freely redistributable.) vfprintf.c should be compiled with
Xthe "-DFLOATLIB" flag if the floating-point conversion options
Xare to be included.
X
XAll of the other members of the "printf() family" are defined in terms
Xof vfprintf(). To my knowledge, all of these (along with the other
Xmath.h functions provided) conform to the relevant portions of the
Xdraft proposed ANSI C standard.
X
XPreliminary versions of several functions traditionally provided in
X"libm" are also included. A few of them are not especially accurate,
Xperhaps to only about 40 bits. They were written in haste and
Xignorance, and will be replaced with provably better routines at the
Xearliest opportunity.
X
Xceil() and floor() truncate numbers to integral floating-point
Xnumbers in different ways. They use modf() to split up the
Xinteger and fraction parts of their arguments.
X
X_poly() and _mult() are internal routines, and are not meant to be
Xcalled by user-level programs. The names are inspired by the Plaugher
X"Safe Math" article. _poly() evaluates a polynomial function with
Xgiven coefficients at a given value. No overflow checking is done, so
Xthe value should be "reduced". _mult() multiplies two numbers and
Xreturns HUGE_VAL (from ) with errno properly set if the result
Xis out of range, or the result otherwise.
X
Xlog() returns the natural logarithm of its argument. The series expansion
Xused was found in A Survey of Numerical Mathematics, and the constants
Xare from the BSD 4.3-Tahoe libm source. log10() is trivially defined
Xusing log().
X
Xexp() uses the argument reduction described in the previous reference.
XThe constants, except for the polynomial coefficient vector, come from
Xthe libm source.
X
Xpow() uses log() and exp(), with a bit of code to handle special cases.
X
Xsqrt() was inspired quite directly by the Plaugher article "Do-it-yourself
XMath Functions". The linear-approximation constants are a least-squares
Xestimator for the square root over [.5,1).
X
X1.7 The EM-file postprocessor
X
XFor portability and machine-independence, the "cem" compiler frontend
Xoutputs floating-point constants in human-readable ASCII notation
Xexactly as they were included in the original source program. It is
Xintended that the code generator handle the machine-dependent
Xconversion to binary representation. However, the "cg" program
Xdistributed with Minix-PC is not able to do this conversion, and simply
Xtreats all float constants as 0.0. (The 1.2-1.3 generator prints a
Xwarning, "Warning: dummy floating point constant(s)".) Someone
Xwith the source to "cg" could add this capability, but this option
Xis not available to everyone (myself included).
X
XTo solve this problem, it is necessary to introduce another pass into
Xthe C compilation process. The "fpp" postprocessor takes the
XEM-assembly output of the "opt" program, and copies it to the output.
XHowever, floating point constants are intercepted and converted to
Xbinary format using atof(). The result is split up and output as
Xeither two or four 16-bit integer constants.
X
XThe result is that the "cg" program never sees floating point constant
Xarguments. The conversion and copy is very fast, but since it is not
Xalways necessary, the "fpp" pass is only run when the "-f" option is
Xgiven to the C compiler driver.
X
XThe EM format documentation mentioned above is, unfortunately, required
Xto understand the logic of the fpp.c program. (I have also written a
Xprogram to convert compact EM-assembly into a sort of human-readable
XEM-assembly (though not identical to the format used in the ACK because
XI have not seen enough to get it right). If you would like a copy of this
Xprogram please write and ask.)
X
X2. REFERENCES
X
X1. ANSI/IEEE, IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE
XStd. 754-1985. New York, N.Y.: The Institute of Electrical and Electronics
XEngineers, Inc., 1985.
X
X2. ANSI/IEEE, IEEE Standard for Radix-Independent Floating-Point Arithmetic,
XANSI/IEEE Std. 854-1987. New York, N.Y.: The Institute of Eletrical and
XElectronics Engineers, Inc., 1987.
X
X3. Cody, William J., and William Waite. Software Manual for the
XElementary Functions, Englewood Cliffs, NJ: Prentice-Hall, 1980.
X
X4. Grehan, Rick. "Some Assembly Required: Floating-Point Without a
XCoprocessor, Part 1," Byte 13(9): pp. 313-319, Sep. 1988.
X
X5. Grehan, Rick. "Some Assembly Required: Floating-Point Without a
XCoprocessor, Part 2," Byte 13(10): pp. 293-298, Oct. 1988.
X
X6. Hart, John F., E.W. Cheney, et al. Computer Approximations, New York:
XRobert E. Krieger Publishing Company, 1978.
X
X7. Kernighan, Brian W., Dennis M. Richie. The C Programming Language,
XSecond Edition. Englewood Cliffs, NJ: Prentice-Hall, 1988.
X
X7. Knuth, Donald E. The Art of Computer Programming, Second Ed., Vol. 2,
XChapter 4. Reading, Mass.: Addison-Wesley, 1981.
X
X8. Motorola, Inc. MC68881/MC68882 Floating-Point Coprocessor User's Manual,
XEnglewood Cliffs, NJ: Prentice-Hall, 1987.
X
X9. Ochs, Tom. "Theory and Practice," Computer Language, 6(3): pp. 67-81,
XMarch 1989.
X
X10. Plaugher, P.J. "Computer Arithmetic," Programming on Purpose, Computer
XLanguage, 5(2): pp. 17-23, Feb. 1988.
X
X11. Plaugher, P.J. "Properties of Floating-point Arithmetic,"
XProgramming on Purpose, Computer Language, 5(3): pp. 17-22, Mar. 1988.
X
X12. Plaugher, P.J. "Safe Math," Programming on Purpose, Computer
XLanguage, 5(5): pp. 17-21, May 1988.
X
X13. Plaugher, P.J. "Do-it-yourself Math Functions," Programming on Purpose,
XComputer Language, 5(6): pp. 17-22, Jun. 1988.
X
X14. Sterbenz, Pat. Floating Point Computation, Englewood Cliffs, NJ:
XPrentice-Hall, 1972.
X
X15. Tanenbaum, Andrew, et al. "A Practical Tool Kit for Making Portable
XCompilers," Communications of the ACM 26(9): pp. 654-660, September 1983.
X
X16. Wilson, Pete. "Floating-Point Survival Kit," Byte 13(3): pp. 217-226,
XMar. 1988.
X
X17. Young, David M., Robert Todd Gregory. A Survey of Mumerical Mathematics,
XVolume I, Reading, Mass: Addison-Wesley, 1972.
END_OF_FILE
if test 23050 -ne `wc -c <'NOTES'`; then
echo shar: \"'NOTES'\" unpacked with wrong size!
fi
# end of 'NOTES'
fi
if test -f 'cfu.x' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cfu.x'\"
else
echo shar: Extracting \"'cfu.x'\" \(3044 characters\)
sed "s/^X//" >'cfu.x' <<'END_OF_FILE'
X.define .cfu
X|
X| floating point => unsigned conversion routines
X| author: Peter S. Housel 6/12/89,6/14/89
X|
X
XBIAS4 = 0x7F - 1
XBIAS8 = 0x3FF - 1
X
X .text
X .globl .cfu
X|
X| on entry dx=source size, cx=dest. size
X|
X.cfu:
X push si | save register variable
X mov si,sp
X
X cmp dx,#4
X jne cfu8
Xcfu4:
X mov bx,4+2(si) | extract exp
X movb dh,bh | extract sign
X shl bx,*1 | shift up one, then down 8
X movb bl,bh
X xorb bh,bh
X
X mov ax,4+2(si) | remove exponent from mantissa
X and ax,#0x7F
X test bx,bx | check for zero exponent - no leading "1"
X jz 0f | for denormalized numbers
X or ax,#0x80 | restore implied leading "1"
X0: mov 4+2(si),ax
X
X cmp bx,#BIAS4 | check exponent
X jl zer4 | strictly fractional, no integer part?
X cmp bx,#BIAS4+32 | is it too big to fit in a 32-bit integer?
X jg toobig
X
X1: cmp bx,#BIAS4+24 | shifted all the way down yet?
X jge 2f
X shr 4+2(si),*1 | shift down to align radix point;
X rcr 4+0(si),*1 | extra bits fall off the end (no rounding)
X inc bx
X jmp 1b
X
X2: cmp bx,#BIAS4+24 | do we have to shift up?
X jle 3f
X shl 4+0(si),*1 | shift up to align radix point
X rcl 4+2(si),*1
X dec bx
X jmp 2b
Xzer4:
X xor ax,ax | make the whole thing zero
X mov 4+0(si),ax
X mov 4+2(si),ax
X
X3: jmp cfu8b | amazingly, we can share the rest of the code
X
Xcfu8:
X cmp dx,#8
X jne ill | illegal EM op
X
X mov bx,4+6(si) | extract exp
X movb dh,bh | extract sign
X shr bx,*1
X shr bx,*1
X shr bx,*1
X shr bx,*1
X and bx,#2047 | kill sign bit
X
X mov ax,4+6(si) | remove exponent from mantissa
X and ax,#0x0F
X test bx,bx | check for zero exponent - no leading "1"
X jz 0f | for denormalized numbers
X or ax,#0x10 | restore implied leading "1"
X0: mov 4+6(si),ax
X
X cmp bx,#BIAS8 | check exponent
X jl zer8 | strictly fractional, no integer part?
X cmp bx,#BIAS8+32 | is it too big to fit in a 32-bit integer?
X jg toobig
X
X1: cmp bx,#BIAS8+53 | shifted all the way down yet?
X jge cfu8b
X shr 4+6(si),*1 | shift down to align radix point;
X rcr 4+4(si),*1 | extra bits fall off the end (no rounding)
X rcr 4+2(si),*1
X rcr 4+0(si),*1
X inc bx
X jmp 1b
Xzer8:
X xor ax,ax | make the whole thing zero
X mov 4+0(si),ax
X mov 4+2(si),ax
X mov 4+4(si),ax
X mov 4+6(si),ax
X
Xcfu8b: cmp cx,#2
X jne cfu8_4
Xcfu8_2: | 8-byte float to 2-byte integer
X mov ax,4+2(si)
X or ax,ax
X jnz toobig | too big to fit into a 16-bit integer?
X mov ax,4+0(si)
X testb dh,dh | is it negative?
X js toobig
X pop si | restore si
X pop bx | save program counter
X xorb dh,dh | dl still contains source size
X add sp,dx | get rid of source value
X push ax | put return value on stack
X push bx | put back return address
X ret
Xcfu8_4: | 8-byte float to 4-byte integer
X cmp cx,#4
X jne ill
X mov ax,4+0(si) | put integer into registers
X mov cx,4+2(si)
X testb dh,dh | is it negative?
X js toobig
X pop si | restore si
X pop bx | save program counter
X xorb dh,dh | dl still contains source size
X add sp,dx | get rid of source value
X push cx | put return value on stack
X push ax
X push bx | put back return address
X ret
Xill:
X pop bx
X jmp .trpilin
X
XECONV = 10
X .globl .fat
Xtoobig:
X mov ax,#ECONV
X push ax
X jmp .fat
END_OF_FILE
if test 3044 -ne `wc -c <'cfu.x'`; then
echo shar: \"'cfu.x'\" unpacked with wrong size!
fi
# end of 'cfu.x'
fi
if test -f 'mlf8.x' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mlf8.x'\"
else
echo shar: Extracting \"'mlf8.x'\" \(5794 characters\)
sed "s/^X//" >'mlf8.x' <<'END_OF_FILE'
X.define .mlf8
X|
X| floating point multiply routine
X| author: Peter S. Housel 4/1/89
X|
X
XU = 14 | offset of multiplier
XV = 6 | offset of multiplicand
XBIAS8 = 0x3FF - 1
X
X .text
X .globl .mlf8
X.mlf8:
X push si
X push di
X mov si,sp | point to arguments
X
X mov bx,6+U(si) | extract u.exp
X movb dh,bh | extract u.sign
X shr bx,*1
X shr bx,*1
X shr bx,*1
X shr bx,*1
X and bx,#2047 | kill sign bit
X
X mov cx,6+V(si) | extract v.exp
X movb dl,ch | extract v.sign
X shr cx,*1
X shr cx,*1
X shr cx,*1
X shr cx,*1
X and cx,#2047 | kill sign bit
X
X mov ax,6+U(si) | remove exponent from u.mantissa
X and ax,#0x0F
X test bx,bx | check for zero exponent - no leading "1"
X jz 0f
X or ax,#0x10 | restore implied leading "1"
X0: mov 6+U(si),ax
X or ax,4+U(si)
X or ax,2+U(si)
X or ax,0+U(si)
X jz retz | multiplying by zero
X
X mov ax,6+V(si) | remove exponent from v.mantissa
X and ax,#0x0F
X test cx,cx | check for zero exponent - no leading "1"
X jz 0f
X or ax,#0x10 | restore implied leading "1"
X0: mov 6+V(si),ax
X or ax,4+V(si)
X or ax,2+V(si)
X or ax,0+V(si)
X jz retz2 | multiplying by zero
X
X xorb dh,dl | xor sign bits for resultant sign
X add bx,cx | add exponents,
X sub bx,#BIAS8+5 | remove excess bias, account for
X | repositioning
X
X xor ax,ax | initialize 128-bit product to zero
X push ax
X push ax
X push ax
X push ax
X push ax
X push ax
X push ax
X push ax
X mov di,sp | di => result
X push dx | save sign
X push bx | save exponent
X
X| see Knuth, Seminumerical Algorithms, section 4.3. algorithm M
X
Xbig0: mov ax,0+U(si) | bigit from multiplier
X test ax,ax
X jz big1 | don't multiply by zero
X mov cx,ax | hold in cx to reduce memory reads
X mul 0+V(si)
X mov 0(di),ax | store into result
X mov bx,dx | save "carry" bigit
X
X mov ax,cx | restore multiplier bigit
X mul 2+V(si)
X| add ax,2(di) | add in bigit so far
X| adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 2(di),ax | store into result
X mov bx,dx
X
X mov ax,cx | restore multiplier bigit
X mul 4+V(si)
X| add ax,4(di) | add in bigit so far
X| adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 4(di),ax | store into result
X mov bx,dx
X
X mov ax,cx | restore multiplier bigit
X mul 6+V(si)
X| add ax,6(di) | add in bigit so far
X| adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 6(di),ax | store into result
X mov 8(di),dx | store carry
X|--
Xbig1: mov ax,2+U(si) | bigit from multiplier
X test ax,ax
X jz big2 | don't multiply by zero
X mov cx,ax | hold in cx to reduce memory reads
X mul 0+V(si)
X add ax,2(di) | add in bigit so far
X adc dx,#0
X mov 2(di),ax | store into result
X mov bx,dx | save "carry" bigit
X
X mov ax,cx | restore multiplier bigit
X mul 2+V(si)
X add ax,4(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 4(di),ax | store into result
X mov bx,dx
X
X mov ax,cx | restore multiplier bigit
X mul 4+V(si)
X add ax,6(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 6(di),ax | store into result
X mov bx,dx
X
X mov ax,cx | restore multiplier bigit
X mul 6+V(si)
X add ax,8(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 8(di),ax | store into result
X mov 10(di),dx | store carry
X|--
Xbig2: mov ax,4+U(si) | bigit from multiplier
X test ax,ax
X jz big3 | don't multiply by zero
X mov cx,ax | hold in cx to reduce memory reads
X mul 0+V(si)
X add ax,4(di) | add in bigit so far
X adc dx,#0
X mov 4(di),ax | store into result
X mov bx,dx | save "carry" bigit
X
X mov ax,cx | restore multiplier bigit
X mul 2+V(si)
X add ax,6(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 6(di),ax | store into result
X mov bx,dx
X
X mov ax,cx | restore multiplier bigit
X mul 4+V(si)
X add ax,8(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 8(di),ax | store into result
X mov bx,dx
X
X mov ax,cx | restore multiplier bigit
X mul 6+V(si)
X add ax,10(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 10(di),ax | store into result
X mov 12(di),dx | store carry
X|--
Xbig3: mov ax,6+U(si) | bigit from multiplier
X test ax,ax
X jz mdone | don't multiply by zero
X mov cx,ax | hold in cx to reduce memory reads
X mul 0+V(si)
X add ax,6(di) | add in bigit so far
X adc dx,#0
X mov 6(di),ax | store into result
X mov bx,dx | save "carry" bigit
X
X mov ax,cx | restore multiplier bigit
X mul 2+V(si)
X add ax,8(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 8(di),ax | store into result
X mov bx,dx
X
X mov ax,cx | restore multiplier bigit
X mul 4+V(si)
X add ax,10(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 10(di),ax | store into result
X mov bx,dx
X
X mov ax,cx | restore multiplier bigit
X mul 6+V(si)
X add ax,12(di) | add in bigit so far
X adc dx,#0
X add ax,bx | add in carry bigit
X adc dx,#0
X mov 12(di),ax | store into result
X mov 14(di),dx | store carry - SHOULD BE ZERO
X|----
Xmdone: pop bx | restore exponent
X pop dx | restore sign
X
X2:
X mov ax,12(di) | multiply (shift) until
X and ax,#0xfff0 | one in "implied" position
X jnz 3f
X shl 0(di),*1
X rcl 2(di),*1
X rcl 4(di),*1
X rcl 6(di),*1
X rcl 8(di),*1
X rcl 10(di),*1
X rcl 12(di),*1
X dec bx | decrement exponent
X jmp 2b
X3:
X movb dl,5(di) | get rounding bits
X mov ax,0(di)
X orb al,4(di)
X or ax,2(di)
X jz 4f
X orb dl,*1 | set "sticky bit" if any low-order set
X4:
X add si,#U | si => u
X add di,#6 | di => most sig words of result
X xchg si,di | reverse for move into u's location
X mov
X mov
X mov
X mov
X add sp,#16 | remove result
X9: pop di | restore register variables
X pop si
X pop cx | save return address
X add sp,#8 | remove v
X push cx | restore return address
X jmp .norm8
X
Xretz2:
X xor ax,ax
X mov 0+U(si),ax
X mov 2+U(si),ax
X mov 4+U(si),ax
X mov 6+U(si),ax
X
Xretz: xor bx,bx | exponent = 0
X xor dx,dx | sign = 0, round bits = 0
X jmp 9b
END_OF_FILE
if test 5794 -ne `wc -c <'mlf8.x'`; then
echo shar: \"'mlf8.x'\" unpacked with wrong size!
fi
# end of 'mlf8.x'
fi
if test -f 'vfprintf.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'vfprintf.c'\"
else
echo shar: Extracting \"'vfprintf.c'\" \(15492 characters\)
sed "s/^X//" >'vfprintf.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley. The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifdef LIBC_SCCS
Xstatic char sccsid[] = "@(#)doprnt.c 5.35 (Berkeley) 6/27/88";
X#endif /* LIBC_SCCS */
X
X#include
X#include
X#include
X#include
X
Xtypedef unsigned char u_char;
Xtypedef unsigned long u_long;
X
X/* 11-bit exponent (VAX G floating point) is 308 decimal digits */
X#define MAXEXP 308
X/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
X#define MAXFRACT 39
X
X#define DEFPREC 6
X
X#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
X
X#define PUTC(ch) (void) putc(ch, fp)
X
X#define ARG() \
X _ulong = flags&LONGINT ? va_arg(argp, long) : \
X flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
X
X#define todigit(c) ((c) - '0')
X#define tochar(n) ((n) + '0')
X
X#define LONGINT 0x01 /* long integer */
X#define LONGDBL 0x02 /* long double; unimplemented */
X#define SHORTINT 0x04 /* short integer */
X#define ALT 0x08 /* alternate form */
X#define LADJUST 0x10 /* left adjustment */
X#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
X#define HEXPREFIX 0x40 /* add 0x or 0X prefix */
X
Xint vfprintf(fp, fmt0, argp)
X register FILE *fp;
X u_char *fmt0;
X va_list argp;
X{
X register u_char *fmt; /* format string */
X register int ch; /* character from fmt */
X register int cnt; /* return value accumulator */
X register int n; /* random handy integer */
X register char *t; /* buffer pointer */
X double _double; /* double precision arguments %[eEfgG] */
X u_long _ulong; /* integer arguments %[diouxX] */
X int base; /* base for [diouxX] conversion */
X int dprec; /* decimal precision in [diouxX] */
X int fieldsz; /* field size expanded by sign, etc */
X int flags; /* flags as above */
X int fpprec; /* `extra' floating precision in [eEfgG] */
X int prec; /* precision from format (%.3d), or -1 */
X int realsz; /* field size expanded by decimal precision */
X int size; /* size of converted field or string */
X int width; /* width from format (%8d), or 0 */
X char sign; /* sign prefix (' ', '+', '-', or \0) */
X char softsign; /* temporary negative sign for floats */
X char *digs; /* digits for [diouxX] conversion */
X char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
X
X fmt = fmt0;
X digs = "0123456789abcdef";
X for (cnt = 0;; ++fmt) {
X if (!(ch = *fmt))
X return (cnt);
X if (ch != '%') {
X PUTC(ch);
X continue;
X }
X flags = 0; dprec = 0; fpprec = 0; width = 0;
X prec = -1;
X sign = '\0';
X
Xrflag: switch (*++fmt) {
X case ' ':
X /*
X * ``If the space and + flags both appear, the space
X * flag will be ignored.''
X * -- ANSI X3J11
X */
X if (!sign)
X sign = ' ';
X goto rflag;
X case '#':
X flags |= ALT;
X goto rflag;
X case '*':
X /*
X * ``A negative field width argument is taken as a
X * - flag followed by a positive field width.''
X * -- ANSI X3J11
X * They don't exclude field widths read from args.
X */
X if ((width = va_arg(argp, int)) >= 0)
X goto rflag;
X width = -width;
X /* FALLTHROUGH */
X case '-':
X flags |= LADJUST;
X goto rflag;
X case '+':
X sign = '+';
X goto rflag;
X case '.':
X if (*++fmt == '*')
X n = va_arg(argp, int);
X else {
X n = 0;
X while (isascii(*fmt) && isdigit(*fmt))
X n = 10 * n + todigit(*fmt++);
X --fmt;
X }
X prec = n < 0 ? -1 : n;
X goto rflag;
X case '0':
X /*
X * ``Note that 0 is taken as a flag, not as the
X * beginning of a field width.''
X * -- ANSI X3J11
X */
X flags |= ZEROPAD;
X goto rflag;
X case '1': case '2': case '3': case '4':
X case '5': case '6': case '7': case '8': case '9':
X n = 0;
X do {
X n = 10 * n + todigit(*fmt);
X } while (isascii(*++fmt) && isdigit(*fmt));
X width = n;
X --fmt;
X goto rflag;
X case 'L':
X flags |= LONGDBL;
X goto rflag;
X case 'h':
X flags |= SHORTINT;
X goto rflag;
X case 'l':
X flags |= LONGINT;
X goto rflag;
X case 'c':
X *(t = buf) = va_arg(argp, int);
X size = 1;
X sign = '\0';
X goto pforw;
X case 'D':
X flags |= LONGINT;
X /*FALLTHROUGH*/
X case 'd':
X case 'i':
X ARG();
X if ((long)_ulong < 0) {
X _ulong = -_ulong;
X sign = '-';
X }
X base = 10;
X goto number;
X#ifdef FLOATLIB
X case 'e':
X case 'E':
X case 'f':
X case 'g':
X case 'G':
X _double = va_arg(argp, double);
X /*
X * don't do unrealistic precision; just pad it with
X * zeroes later, so buffer size stays rational.
X */
X if (prec > MAXFRACT) {
X if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
X fpprec = prec - MAXFRACT;
X prec = MAXFRACT;
X }
X else if (prec == -1)
X prec = DEFPREC;
X /*
X * softsign avoids negative 0 if _double is < 0 and
X * no significant digits will be shown
X */
X if (_double < 0) {
X softsign = '-';
X _double = -_double;
X }
X else
X softsign = 0;
X /*
X * cvt may have to round up past the "start" of the
X * buffer, i.e. ``intf("%.2f", (double)9.999);'';
X * if the first char isn't NULL, it did.
X */
X *buf = NULL;
X size = cvt(_double, prec, flags, &softsign, *fmt, buf,
X buf + sizeof(buf));
X if (softsign)
X sign = '-';
X t = *buf ? buf : buf + 1;
X goto pforw;
X#endif FLOATLIB
X case 'n':
X if (flags & LONGINT)
X *va_arg(argp, long *) = cnt;
X else if (flags & SHORTINT)
X *va_arg(argp, short *) = cnt;
X else
X *va_arg(argp, int *) = cnt;
X break;
X case 'O':
X flags |= LONGINT;
X /*FALLTHROUGH*/
X case 'o':
X ARG();
X base = 8;
X goto nosign;
X case 'p':
X /*
X * ``The argument shall be a pointer to void. The
X * value of the pointer is converted to a sequence
X * of printable characters, in an implementation-
X * defined manner.''
X * -- ANSI X3J11
X */
X /* NOSTRICT */
X _ulong = (u_long)va_arg(argp, void *);
X base = 16;
X goto nosign;
X case 's':
X if (!(t = va_arg(argp, char *)))
X t = "(null)";
X if (prec >= 0) {
X /*
X * can't use strlen; can only look for the
X * NUL in the first `prec' characters, and
X * strlen() will go further.
X */
X char *p, *memchr();
X
X if (p = memchr(t, 0, prec)) {
X size = p - t;
X if (size > prec)
X size = prec;
X } else
X size = prec;
X } else
X size = strlen(t);
X sign = '\0';
X goto pforw;
X case 'U':
X flags |= LONGINT;
X /*FALLTHROUGH*/
X case 'u':
X ARG();
X base = 10;
X goto nosign;
X case 'X':
X digs = "0123456789ABCDEF";
X /* FALLTHROUGH */
X case 'x':
X ARG();
X base = 16;
X /* leading 0x/X only if non-zero */
X if (flags & ALT && _ulong != 0)
X flags |= HEXPREFIX;
X
X /* unsigned conversions */
Xnosign: sign = '\0';
X /*
X * ``... diouXx conversions ... if a precision is
X * specified, the 0 flag will be ignored.''
X * -- ANSI X3J11
X */
Xnumber: if ((dprec = prec) >= 0)
X flags &= ~ZEROPAD;
X
X /*
X * ``The result of converting a zero value with an
X * explicit precision of zero is no characters.''
X * -- ANSI X3J11
X */
X t = buf + BUF;
X if (_ulong != 0 || prec != 0) {
X do {
X *--t = digs[_ulong % base];
X _ulong /= base;
X } while (_ulong);
X digs = "0123456789abcdef";
X if (flags & ALT && base == 8 && *t != '0')
X *--t = '0'; /* octal leading 0 */
X }
X size = buf + BUF - t;
X
Xpforw:
X /*
X * All reasonable formats wind up here. At this point,
X * `t' points to a string which (if not flags&LADJUST)
X * should be padded out to `width' places. If
X * flags&ZEROPAD, it should first be prefixed by any
X * sign or other prefix; otherwise, it should be blank
X * padded before the prefix is emitted. After any
X * left-hand padding and prefixing, emit zeroes
X * required by a decimal [diouxX] precision, then print
X * the string proper, then emit zeroes required by any
X * leftover floating precision; finally, if LADJUST,
X * pad with blanks.
X */
X
X /*
X * compute actual size, so we know how much to pad
X * fieldsz excludes decimal prec; realsz includes it
X */
X fieldsz = size + fpprec;
X if (sign)
X fieldsz++;
X if (flags & HEXPREFIX)
X fieldsz += 2;
X realsz = dprec > fieldsz ? dprec : fieldsz;
X
X /* right-adjusting blank padding */
X if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
X for (n = realsz; n < width; n++)
X PUTC(' ');
X /* prefix */
X if (sign)
X PUTC(sign);
X if (flags & HEXPREFIX) {
X PUTC('0');
X PUTC((char)*fmt);
X }
X /* right-adjusting zero padding */
X if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
X for (n = realsz; n < width; n++)
X PUTC('0');
X /* leading zeroes from decimal precision */
X for (n = fieldsz; n < dprec; n++)
X PUTC('0');
X
X /* the string or number proper */
X for (n = size; --n >= 0; )
X PUTC(*t++);
X /* trailing f.p. zeroes */
X while (--fpprec >= 0)
X PUTC('0');
X /* left-adjusting padding (always blank) */
X if (flags & LADJUST)
X for (n = realsz; n < width; n++)
X PUTC(' ');
X /* finally, adjust cnt */
X cnt += width > realsz ? width : realsz;
X break;
X case '\0': /* "%?" prints ?, unless ? is NULL */
X return (cnt);
X default:
X PUTC((char)*fmt);
X cnt++;
X }
X }
X /* NOTREACHED */
X}
X
X#ifdef FLOATLIB
Xstatic
Xcvt(number, prec, flags, signp, fmtch, startp, endp)
X double number;
X register int prec;
X int flags;
X u_char fmtch;
X char *signp, *startp, *endp;
X{
X register char *p, *t;
X register double fract;
X int dotrim, expcnt, gformat;
X double integer, tmp, modf();
X char *exponent(), *round();
X
X dotrim = expcnt = gformat = 0;
X fract = modf(number, &integer);
X
X /* get an extra slot for rounding. */
X t = ++startp;
X
X /*
X * get integer portion of number; put into the end of the buffer; the
X * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
X */
X for (p = endp - 1; integer; ++expcnt) {
X tmp = modf(integer / 10, &integer);
X *p-- = tochar((int)((tmp + .01) * 10));
X }
X switch(fmtch) {
X case 'f':
X /* reverse integer into beginning of buffer */
X if (expcnt)
X for (; ++p < endp; *t++ = *p);
X else
X *t++ = '0';
X /*
X * if precision required or alternate flag set, add in a
X * decimal point.
X */
X if (prec || flags&ALT)
X *t++ = '.';
X /* if requires more precision and some fraction left */
X if (fract) {
X if (prec)
X do {
X fract = modf(fract * 10, &tmp);
X *t++ = tochar((int)tmp);
X } while (--prec && fract);
X if (fract)
X startp = round(fract, (int *)NULL, startp,
X t - 1, (char)0, signp);
X }
X for (; prec--; *t++ = '0');
X break;
X case 'e':
X case 'E':
Xeformat: if (expcnt) {
X *t++ = *++p;
X if (prec || flags&ALT)
X *t++ = '.';
X /* if requires more precision and some integer left */
X for (; prec && ++p < endp; --prec)
X *t++ = *p;
X /*
X * if done precision and more of the integer component,
X * round using it; adjust fract so we don't re-round
X * later.
X */
X if (!prec && ++p < endp) {
X fract = 0;
X startp = round((double)0, &expcnt, startp,
X t - 1, *p, signp);
X }
X /* adjust expcnt for digit in front of decimal */
X --expcnt;
X }
X /* until first fractional digit, decrement exponent */
X else if (fract) {
X /* adjust expcnt for digit in front of decimal */
X for (expcnt = -1;; --expcnt) {
X fract = modf(fract * 10, &tmp);
X if (tmp)
X break;
X }
X *t++ = tochar((int)tmp);
X if (prec || flags&ALT)
X *t++ = '.';
X }
X else {
X *t++ = '0';
X if (prec || flags&ALT)
X *t++ = '.';
X }
X /* if requires more precision and some fraction left */
X if (fract) {
X if (prec)
X do {
X fract = modf(fract * 10, &tmp);
X *t++ = tochar((int)tmp);
X } while (--prec && fract);
X if (fract)
X startp = round(fract, &expcnt, startp,
X t - 1, (char)0, signp);
X }
X /* if requires more precision */
X for (; prec--; *t++ = '0');
X
X /* unless alternate flag, trim any g/G format trailing 0's */
X if (gformat && !(flags&ALT)) {
X while (t > startp && *--t == '0');
X if (*t == '.')
X --t;
X ++t;
X }
X t = exponent(t, expcnt, fmtch);
X break;
X case 'g':
X case 'G':
X /* a precision of 0 is treated as a precision of 1. */
X if (!prec)
X ++prec;
X /*
X * ``The style used depends on the value converted; style e
X * will be used only if the exponent resulting from the
X * conversion is less than -4 or greater than the precision.''
X * -- ANSI X3J11
X */
X if (expcnt > prec || !expcnt && fract && fract < .0001) {
X /*
X * g/G format counts "significant digits, not digits of
X * precision; for the e/E format, this just causes an
X * off-by-one problem, i.e. g/G considers the digit
X * before the decimal point significant and e/E doesn't
X * count it as precision.
X */
X --prec;
X fmtch -= 2; /* G->E, g->e */
X gformat = 1;
X goto eformat;
X }
X /*
X * reverse integer into beginning of buffer,
X * note, decrement precision
X */
X if (expcnt)
X for (; ++p < endp; *t++ = *p, --prec);
X else
X *t++ = '0';
X /*
X * if precision required or alternate flag set, add in a
X * decimal point. If no digits yet, add in leading 0.
X */
X if (prec || flags&ALT) {
X dotrim = 1;
X *t++ = '.';
X }
X else
X dotrim = 0;
X /* if requires more precision and some fraction left */
X if (fract) {
X if (prec) {
X do {
X fract = modf(fract * 10, &tmp);
X *t++ = tochar((int)tmp);
X } while(!tmp);
X while (--prec && fract) {
X fract = modf(fract * 10, &tmp);
X *t++ = tochar((int)tmp);
X }
X }
X if (fract)
X startp = round(fract, (int *)NULL, startp,
X t - 1, (char)0, signp);
X }
X /* alternate format, adds 0's for precision, else trim 0's */
X if (flags&ALT)
X for (; prec--; *t++ = '0');
X else if (dotrim) {
X while (t > startp && *--t == '0');
X if (*t != '.')
X ++t;
X }
X }
X return(t - startp);
X}
X
Xstatic char *
Xround(fract, exp, start, end, ch, signp)
X double fract;
X int *exp;
X register char *start, *end;
X char ch, *signp;
X{
X double tmp;
X
X if (fract)
X (void)modf(fract * 10, &tmp);
X else
X tmp = todigit(ch);
X if (tmp > 4)
X for (;; --end) {
X if (*end == '.')
X --end;
X if (++*end <= '9')
X break;
X *end = '0';
X if (end == start) {
X if (exp) { /* e/E; increment exponent */
X *end = '1';
X ++*exp;
X }
X else { /* f; add extra digit */
X *--end = '1';
X --start;
X }
X break;
X }
X }
X /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
X else if (*signp == '-')
X for (;; --end) {
X if (*end == '.')
X --end;
X if (*end != '0')
X break;
X if (end == start)
X *signp = 0;
X }
X return(start);
X}
X
Xstatic char *
Xexponent(p, exp, fmtch)
X register char *p;
X register int exp;
X u_char fmtch;
X{
X register char *t;
X char expbuf[MAXEXP];
X
X *p++ = fmtch;
X if (exp < 0) {
X exp = -exp;
X *p++ = '-';
X }
X else
X *p++ = '+';
X t = expbuf + MAXEXP;
X if (exp > 9) {
X do {
X *--t = tochar(exp % 10);
X } while ((exp /= 10) > 9);
X *--t = tochar(exp);
X for (; t < expbuf + MAXEXP; *p++ = *t++);
X }
X else {
X *p++ = '0';
X *p++ = tochar(exp);
X }
X return(p);
X}
X#endif FLOATLIB
END_OF_FILE
if test 15492 -ne `wc -c <'vfprintf.c'`; then
echo shar: \"'vfprintf.c'\" unpacked with wrong size!
fi
# end of 'vfprintf.c'
fi
echo shar: End of archive 1 \(of 3\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 3 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0