%% /u/sy/beebe/src/elefunt/java/README, Thu May 30 05:57:30 2002 %% Edit by Nelson H. F. Beebe *********************************************** *********************************************** ** Extended Java Version of the Code & Waite ** ** ELEFUNT Elementary Function Test Package ** ** [30-May-2002]--[07-Jun-2002] ** *********************************************** *********************************************** by Nelson H. F. Beebe Center for Scientific Computing University of Utah Department of Mathematics, 110 LCB 155 S 1400 E RM 233 Salt Lake City, UT 84112-0090 USA Email: beebe@math.utah.edu, beebe@acm.org, beebe@computer.org, beebe@ieee.org (Internet) WWW URL: http://www.math.utah.edu/~beebe Telephone: +1 801 581 5254 FAX: +1 801 585 1640, +1 801 581 4148 ================= Table of contents ================= Preface Introduction to the Java version The pros and cons of Java What's new How to run the ELEFUNT tests References Introduction to the C/C++ version ======= Preface ======= To get started immediately, with minimal reading, skip down to the section ``How to run the ELEFUNT tests''. ================================ Introduction to the Java version ================================ This is a manual translation into Java of the companion C/C++ manual translation of the Fortran ELEFUNT packages. As with the C/C++ version, the goal is NOT to exercise all of the bells and whistles of the newer languages, but rather to preserve the code structure as closely as possible to the original Fortran, and in particular, to make the output from ALL of the various language implementations indistinguishable. Thus, no attempt has been made to use lowercase letters in strings. For reference purposes, each Java test program produces a leading one-line banner identifying the version and last modification time of the elefunt.java support file. The syntax of large parts of C is identical to that of Java. Java has a radically different I/O model, and completely lacks pointers, but fortunately, the ELEFUNT code in C makes practically no use of pointers. Java is object oriented, so class wrappers need to added. The manual translation of the C/C++ test programs into Java took only about twenty minutes each, thanks to the power of the emacs text editor, its Lisp extension language, regular-expression support, and keyboard macros. The entire job was completed in just over one day, which is not a bad investment for the production of just under 7000 lines of Java code! I began by inserting a boilerplate class wrapper, then inserted the entire body of the test program, indented four additional spaces, into the corresponding Java function. Next, I cleaned up the variable declarations, since I chose to define several C variables as Java final constants (Java's "final int foo = 123;" is superior to the C/C++ preprocessor style "#define foo 123", since it gives a type as well as a name, and prevents reassignment). Then I ran the Emacs Lisp function java-convert-c-formats() to convert format items in C printf() statements to Java function call templates: this converted a C statement like (void)printf("The answers are %7.3f and %14.5e\n", result1, result2); into a pending Java statement System.out.print("The answers are " + fmt.F(,7,3) + " and " + fmt.E(,14,5) + "\n", result1, result2); I repeatedly applied a keyboard macro to the source code to change those incomplete statements to look like this: System.out.print("The answers are " + fmt.F(result1,7,3) + " and " + fmt.E(result2,14,5) + "\n"); I then cleaned up the code by manually wrapping several long lines, and finally, I applied the Emacs Lisp function java-convert-machar-names() to convert names formerly set by the call to machar() to package-qualified names, since in Java, machar() is not required, and its arguments simply become named constants. It was gratifying that in EVERY case, once a Java compilation was successful, the programs ran correctly, and gave the expected output. Once the double-precision Java version was completed, it was a straightforward task to translate it to the single-precision version, which is mostly a matter of changing "double" to "float", and adding suitable typecasts in some expressions, and F suffixes on floating-point constants. Once again, all of the test programs ran successfully and correctly after their first successful compilation. ========================= The pros and cons of Java ========================= The Java programming language is defined in terms of an abstract virtual machine that functions identically on all hardware platforms. The intent was to create a programming language environment that would shield software developers from the variations across platforms that must be attended to in virtually all other programming languages. In the quest for the goal `write once, run everywhere', Java imposes a substantial number of restrictions that most other programming languages do not. In particular, its evaluation order is rigidly defined as left-to-right (subject to parentheses and operator precedence), it does not permit mixing of single- and double-precision arithmetic without explicit typecasts, and it does not permit evaluation of intermediate expressions in higher precision. Java classes must be stored in files of the same name, with extension .java. Compilation with javac produces a corresponding .class file, analogous to the object files (.o on UNIX, .obj on DOS, Windows, TOPS-20, DEC (Open)VMS, ...) of other languages. This necessarily forces an organizational discipline of one class == one file. Interestingly, unlike other languages, Java programs can have multiple main programs (though at most one per class), and some implementations (e.g., GNU gcj) even permit Java programs to start from arbitrary functions! This proves very convenient: a main() program provided with each .java file can run validation tests, e.g., javac fmt.java && java fmt Java's arithmetic is identical on all platforms: it is based on 8-bit, 16-bit, 32-bit, and 64-bit two's complement signed integers, a 16-bit unsigned char integer type, and 32-bit and 64-bit floating-point numbers represented in IEEE 754 format. Java requires full support of IEEE 754 subnormals, NaN, Infinity, and signed zero. However, Java omits rounding control and access to floating-point flags, and has a number of other vagaries that prompted W. Kahan and Joseph D. Darcy to write a scathing criticism entitled ``How Java's Floating-Point Hurts Everyone Everywhere'' [see the references below.] Java has attracted enormous attention: my Java bibliographies at http://www.math.utah.edu/pub/tex/bib/index-table-j.html#java http://www.math.utah.edu/pub/tex/bib/index-table-j.html#java2000 log 1918 books published from 1995 to mid-2002, nearly 300 a year, vastly more than any other programming language in the history of computing. By contrast, my Fortran bibliographies record 1643 books from 1961 to 2001, or about 40 a year. Java's superficial resemblance to a subset of C may give an initial impression of simplicity, but there is enormous complexity concealed in the huge class libraries, and there are astonishingly many pitfalls in Java, as documented in Bloch's excellent book (see references below). Java's core library reference manual fills three volumes of about 3600 pages (see the books by co-authored by Chan, Lee, and Kramer in the references below), and there are many thousands of book pages on its several other libraries (AWT, Java Beans, JNI, Jini, RMI, Swing, ...). The source distribution in Java 1.4 (the latest version: on Sun Solaris 2.8, available in the single archive file /usr/j2se/src.zip) includes 1,180,000 lines of code, and that is incomplete, since some modules are not distributed in source form, or are implemented in native code (e.g., much of the java.lang.Math library), and neither are the compilers, debuggers, linkers, byte-code verifiers, and Java Virtual Machine interpreters included. Yet, for all of that code, Java has some appalling omissions that clearly demonstrate that its developers had virtually no concern for, or understanding of, numeric applications. Many of these issues have been taken up by the Java Grande Forum (visit http://www.javagrande.org/, and see many papers recorded in the Java bibliographies noted above), a consortium of institutions and individuals interested in Java for numerical computation. For the ELEFUNT test package, three issues in particular stand out: (1) Despite its huge library corpus, Java has almost no support whatever for format control of numeric output: its designers foolishly assume that there can be only one text representation of a number. Fortran had such control back in 1956, and so does C, C++, and most Lisp dialects. Even little languages like Pascal, awk, perl, python, ruby, ... have it. Java does not. (2) Like C before its second ISO Standard, in 1999, Java tries to squeak by with minimal floating-point library support: it offers remainder, absolute value, conversion to integer (truncation with a cast, plus ceil(), floor(), and round()), power, exponential, logarithm, random number, trigonometric functions (cos(), sin(), tan()), and the inverse trigonometric functions (acos(), asin(), atan(), and atan2()). However, only double-precision versions of these functions are provided: there are none for single-precision computation. [See http://java.sun.com/j2se/1.4/docs/api/java/lang/Math.html for complete documentation of class java.lang.Math.] Absent are log10(), cotan(), and hyperbolic functions (cosh(), sinh(), tanh()) included in Cody & Waite's 1980 book, Software Manual for the Elementary Functions, and standardly available in Fortran, C, and C++. Also absent are the special functions, such erf(), erfc(), gamma(), psi(), and Bessel functions (J(n,x), I(n,x), K(n,x), and Y(n,x)), commonly provided in UNIX C libraries. These deficiencies are significant not only for numerical programmers, but they also impede using Java for pedagogical purposes: how can students learn about the issue of floating-point precision if there is effectively only one available for experimentation? (3) There is no support whatever for quadruple precision, since that is not part of the Java Virtual Machine specification. The most serious of these is (1), and to deal with it, I initially wrote a modest package, fmt.java, to provide functions I(x,w), E(x,w,d), and F(x,w,d), analogous to the Fortran Iw, Ew.d, and Fw.d format items, since these are all that are required for the ELEFUNT tests. Although all Java objects and primitive types can be converted to a string simply by concatenating them with another string (e.g., "" + x), there is no control over the representation: floating-point numbers may or may not have an exponent, and the number of exponent digits is always minimal. The number of digits output is one less than required by Matula's 1968 formula of ceil(1 + N/log2(10)) [see references below] for N bits of precision, so reconversion of the decimal representation to binary is not guaranteed to recover the original value. However, failures for random arguments in (0,1) are unlikely: 100,000,000 binary->decimal->binary conversion tests in bugs/bug001.java found none in the interval (0,1), and the same number of tests in bugs/bug002.java found none in the intervals (Float.MIN_VALUE,1) and (1,Float.MAX_VALUE) [each test took two hours wall clock time on a 1.266GHz Intel Pentium 4.] I therefore spent time on the four days following the first successful Java translation of ELEFUNT, writing these notes, carrying out additional testing on several other platforms, implementing an enhanced version of the extmath.java package to supply standard elementary functions that are not provided by Java, and writing a replacement for the simple fmt.java package as the pair fmtint.java and fmtflt.java. The latter two were the most difficult: together they contain nearly 5200 lines, of which half is test suite code, and a quarter is documentation formatted according to the javadoc conventions: running javadoc -author -version fmt???.java produces the HTML documentation stored in the ./html directory. The goal in the fmt.java package is not to achieve complete rigor (for that, see the papers by Clinger, Gries, Knuth, Steele and White, Burger and Dybvig, and Abbott and 15 Al's in the references below, and note that multiple-precision arithmetic, completely lacking in Java, is mandatory for the job), but rather, to provide a reasonably straightforward implementation that is acceptably accurate for ELEFUNT output. Ultimately, Java will probably get a fancy numeric formatting package that my fmt.java package can then interface with. Given Sun Microsystem's strong track record in providing high-quality floating-point support, thanks to people like IEEE 754 committee members David Hough and Joe Darcy, and to Guy Steele (the same one referenced above), I have some confidence that Java will ultimately benefit from this in-house knowledge base. I have not retrofitted use of the fancier fmtflt.java and fmtint.java packages into the Java version of the ELEFUNT package, but I expect to make good use of them in future Java programming projects. In tests of the fmtflt.java and fmtint.java packages on local systems, I get identical output on Apple PowerPC Darwin (MacOSX), Intel x86 GNU/Linux, and Sun Solaris, covering Java 1.1, 1.2, 1.2.2, 1.3.1, and 1.4. There are numeric differences reported on Compaq/DEC Alpha OSF/1 and SGI IRIX 6.5 systems: in every case, these differences are in the formatting of numbers by the native Java libraries, not in those from my own code. Java provides object wrappers for each of its primitive data types, with similar names (primitive "double" becomes object "Double"). These wrappers provide a few named constants (MAX_VALUE, MIN_VALUE, NEGATIVE_INFINITY, NaN, and POSITIVE_INFINITY, but none of the other values provided by machar()), plus a few methods for value conversion, infinity, NaN, and object equality testing, conversion to raw bit strings, and object hash codes. Methods then are used with object names: the primitive "double x; fmt.E(x,w,d)" would become "ExtendedDouble xx; xx.E(w,d)", where ExtendedDouble is a class that implements an extension to Double, and offers additional methods. In ELEFUNT for C/C++, I extended the code to permit both compile-time and run-time setting of the initial pseudo-random number generator seed, and of the number of random arguments in the test intervals. At run-time, values can be set for the environment variables INITIALSEED and MAXTEST. Java's virtual machine environment tends to divorce it from access to the underlying host environment, so there is no access to shell environment variables via getenv(). However, a similar feature can be provided at run time with Java `system properties' accessed via the function System.getProperty(): java -DINITIALSEED=271828182 -DMAXTEST=100000 talldp I have yet to discover how, or if, the GNU Java implementation, gcj, accesses such properties. Neither environment variables nor command-line variable assignments are visible to its System.getProperty(). ========== What's new ========== * ELEFUNT is now available for Java! * Java code has been successful compiled with Java 1.2, 1.3, and 1.4, with deprecation warnings turned on. It should work correctly, without changes, in ALL Java platforms. Actual output is expected to vary, since some vendors might use differing implementations of the java.lang.Math library. It has also been compiled with GNU gcj 3.0.4 on GNU/Linux on Intel IA-32, and gcj 3.1 on Sun SPARC Solaris 2.8: while compilations are successful, runs all fail with an uncaught divide-by-zero error inside the runtime library from the call myFormat.format(-999.0) in fmt.java. This was tedious to track down: the gdb debugger does not yet support gcj-compiled Java code, and the Runtime.traceInstructions() and Runtime.traceMethodCalls functions are not supported, so I had to resort to dozens of print statements sprinkled through a temporary copy of the source code. * The extmath.java package supplies standard elementary functions that are missing in the definition of the standard java.lang.Math package. It can be used as a complete replacement for the latter: simply change all instances of Math.X to extmath.X in your code, for all X. * The fmtflt.java and fmtint.java packages provide much enhanced numeric formatted output, with support for string justification (left, right, center), Ada-style based numbers (5#34214#), Fortran/C/C++ format items (B, I, O, Z, E, F, G, plus new ones R and S), and Ada-style digit separators (contrast 3.1415926535897932384626433832795028 with 3.14159_26535_89793_23846_26433_83279_5028 or 3.141_592_653_589_793_238_462_643_383_279_502_8). * New ELEFUNT code directory structure, with common source files, shell scripts, and awk programs in ./common, and precision-dependent code in ./sp (single precision) and ./dp (double precision). * Output listings for several current systems are available in ./sp/logs and ./dp/logs. * New top-level Makefile to control building and testing. * New helper script (./common/elefunt.sh) to run the tests with several different Java compilers, giving the output listing distinctive names that identify the system, compiler, and optimization level * (cd common; make check) will run a validation suite against correct output from Java 1.2 on Sun Solaris 2.8. In particular, this does simple tests for fmt.java, and extensive tests for extmath.java, fmtflt.java, and fmtint.java. The extmath.java tests are carefully chosen to examine regions around the cutoffs used in my implementations of the hyperbolic functions, as well as for signed zero, and near the underflow and overflow limits of these functions, and those that they call to do their computations. The tests also include results for alternate implementations using the standard mathematical definitions, and using truncated Taylor series expansions, which is also handy for pedagogical demonstrations of the intricacies of floating-point computation. On Sun Solaris 2.8, identical results are obtained for extmath.java for Java 1.1, 1.2, and 1.4. On Apple Darwin (== MacOS X), Java 1.3.1 produces identical output. On Intel IA-32 GNU/Linux (Red Hat 7.2), Java 1.2.2 produces identical output. On SGI IRIX 6.5, Java 1.3. two test results (for sinh() and cosh() near the overflow limit) differ by 2 ulps from the correct values. On Compaq/DEC OSF/1 4.0, the same tests as on the SGI were also 2 ulps in error. However, the tests exposed another problem: on this system (long)NaN is -9223372036854775808, whereas on all of the other test systems, (long)NaN is 0! This is demonstrated in the program bugs/bug002.java. * doc/*.pdf contain additional documentation on the computation of elementary functions. * html/*.* contains javadoc HTML documentation produced automatically from the fmtflt.java and fmtint.java packages. ============================ How to run the ELEFUNT tests ============================ UNIX make is the conventional, and best, way to automate software building and testing. The Makefiles here are highly portable, provide all of the GNU standard targets (notably: all, check, clean, distclean, install, maintainer-clean, mostlyclean, and uninstall), and should not need modification at any site. The packages are portable enough that, so far, there has been no need to provide for automatic configuration with the GNU autoconf package: thus, there are no configure scripts. There are two convenient ways to run the ELEFUNT test programs: make all or make elefunt These run both single- and double-precision tests, since both are standard in Java. The difference between "all" and "elefunt" is that with the former, you can optionally additionally supply on the make command line * output filename suffix (NAME=...), * additional compiler flags (JAVACFLAGS=...), * additional make flags (XMFLAGS=...), and * compiler optimization level (XOPT=...) while with the latter, the ./common/elefunt.sh script takes over, figures out what system you have, and runs the tests with at least two optimization levels of each compiler. To restore the distribution tree to its original condition (but preserving any listing files that you generated locally), do make distclean ========== References ========== @String{j-CACM = "Communications of the Association for Computing Machinery"} @String{j-IBM-JRD = "IBM Journal of Research and Development"} @String{j-PROC-AM-MATH-SOC = "Proceedings of the American Mathematical Society"} @String{j-SIGPLAN = "ACM SIGPLAN Notices"} @String{pub-AW = "Ad{\-d}i{\-s}on-Wes{\-l}ey"} @String{pub-AW:adr = "Reading, MA, USA"} @String{pub-SV = "Spring{\-}er-Ver{\-}lag"} @String{pub-SV:adr = "Berlin, Germany~/ Heidelberg, Germany~/ London, UK~/ etc."} @Article{Matula:1968:BCT, author = "David W. Matula", title = "The Base Conversion Theorem", journal = j-PROC-AM-MATH-SOC, volume = "19", number = "3", pages = "716--723", month = jun, year = "1968", CODEN = "PAMYAR", ISSN = "0002-9939", bibdate = "Fri Apr 21 07:26:39 2000", acknowledgement = ack-nhfb, } @Article{Matula:1968:IOC, author = "D. W. Matula", title = "In-and-Out Conversions", journal = j-CACM, volume = "11", number = "1", pages = "47--50", month = jan, year = "1968", CODEN = "CACMA2", ISSN = "0001-0782", bibdate = "Thu Sep 1 10:16:10 1994", bibsource = "ftp://garbo.uwasa.fi/pc/doc-soft/fpbibl18.zip", acknowledgement = ack-nj, } @Article{Clinger:1990:HRF, author = "William D. Clinger", title = "How to Read Floating Point Numbers Accurately", journal = j-SIGPLAN, volume = "25", number = "6", pages = "92--101", month = jun, year = "1990", CODEN = "SINODQ", ISSN = "0362-1340", bibdate = "Sun May 02 09:17:14 1999", bibsource = "ftp://garbo.uwasa.fi/pc/doc-soft/fpbibl18.zip", note = "See also output algorithms in \cite{Knuth:1990:SPW,Steele:1990:HPF,Burger:1996:PFN,Abbott:1999:ASS}.", abstract = "Consider the problem of converting decimal scientific notation for a number into the best binary floating point approximation to that number, for some fixed precision. This problem cannot be solved using arithmetic of any fixed precision. Hence the IEEE Standard for Binary Floating-Point Arithmetic does not require the result of such a conversion to be the best approximation. The author presents an efficient algorithm that always finds the best approximation. The algorithm uses a few extra bits of precision to compute an IEEE-conforming approximation while testing an intermediate result to determine whether the approximation could be other than the best. If the approximation might not be the best, then the best approximation is determined by a few simple operations on multiple-precision integers, where the precision is determined by the input. When using 64 bits of precision to compute IEEE double precision results, the algorithm avoids higher-precision arithmetic over 99\% of the time.", acknowledgement = ack-nhfb # " and " # ack-nj, affiliation = "Oregon Univ., Eugene, OR, USA", classification = "C5230 (Digital arithmetic methods); C1160 (Combinatorial mathematics); C7310 (Mathematics)", confdate = "20-22 June 1990", conflocation = "White Plains, NY, USA", confsponsor = "ACM", keywords = "Floating point numbers; Decimal scientific notation; Best binary floating point approximation; Fixed precision; IEEE Standard; Efficient algorithm; IEEE-conforming approximation; Intermediate result; Multiple-precision integers; IEEE double precision results; Higher-precision arithmetic", language = "English", pubcountry = "USA", thesaurus = "Digital arithmetic; Mathematics computing; Number theory; Standards", } @InCollection{Gries:1990:BDO, author = "David Gries", title = "Binary to Decimal, One More Time", crossref = "Feijen:1990:BOB", chapter = "16", pages = "141--148", year = "1990", bibdate = "Sat Sep 03 09:41:32 1994", note = "This paper presents an alternate proof of Knuth's algorithm \cite{Knuth:1990:SPW} for conversion between decimal and fixed-point binary numbers.", acknowledgement = ack-nhfb, } @InCollection{Knuth:1990:SPW, author = "Donald E. Knuth", title = "A Simple Program Whose Proof Isn't", crossref = "Feijen:1990:BOB", chapter = "27", pages = "233--242", year = "1990", bibdate = "Sat Sep 03 09:42:46 1994", note = "This paper discusses the algorithm used in {\TeX} for converting between decimal and scaled fixed-point binary values, and for guaranteeing a minimum number of digits in the decimal representation. See also \cite{Clinger:1990:HRF} for decimal to binary conversion, \cite{Steele:1990:HPF} for binary to decimal conversion, and \cite{Gries:1990:BDO} for an alternate proof of Knuth's algorithm.", acknowledgement = ack-nhfb, } @Article{Steele:1990:HPF, author = "Guy L. {Steele Jr.} and Jon L. White", title = "How to Print Floating-Point Numbers Accurately", journal = j-SIGPLAN, volume = "25", number = "6", pages = "112--126", month = jun, year = "1990", CODEN = "SINODQ", ISSN = "0362-1340", bibdate = "Sat May 04 17:29:18 1996", note = "See also input algorithm in \cite{Clinger:1990:HRF}, and a faster output algorithm in \cite{Burger:1996:PFN}, and \cite{Knuth:1990:SPW}, and IBM S/360 algorithms in \cite{Abbott:1999:ASS} for both IEEE 754 and S/360 formats. In electronic mail dated Wed, 27 Jun 90 11:55:36 EDT, Guy Steele reported that an intrepid pre-SIGPLAN 90 conference implementation of what is stated in the paper revealed 3 mistakes: \begin{itemize} \item[1.] Table~5 (page 124):\par\noindent insert {\tt k <-- 0} after assertion, and also delete {\tt k <-- 0} from Table~6. \item[2.] Table~9 (page 125):\par\noindent \begin{tabular}{ll} for & {\tt -1:USER!({"}{"});} \\ substitute & {\tt -1:USER!({"}0{"});} \end{tabular}\par\noindent and delete the comment. \item[3.] Table~10 (page 125):\par\noindent \begin{tabular}{ll} for & {\tt fill(-k, {"}0{"})}\\ substitute & {\tt fill(-k-1, {"}0{"})} \end{tabular} \end{itemize} \def\EatBibTeXPeriod#1{\ifx#1.\else#1\fi}\EatBibTeXPeriod", abstract = "Algorithms are presented for accurately converting floating-point numbers to decimal representation. The key idea is to carry along with the computation an explicit representation of the required rounding accuracy. The authors begin with the simpler problem of converting fixed-point fractions. A modification of the well-known algorithm for radix-conversion of fixed-point fractions by multiplication explicitly determines when to terminate the conversion process; a variable number of digits are produced. They derive two algorithms for free-format output of floating-point numbers. Finally, they modify the free-format conversion algorithm for use in fixed-format applications. Information may be lost if the fixed format provides too few digit positions, but the output is always correctly rounded. On the other hand, no `garbage digits' are ever produced, even if the fixed format specifies too many digit positions (intuitively, the `4/3 prints as 1.333333328366279602' problem does not occur).", acknowledgement = ack-nhfb, affiliation = "Thinking Machines Corp., Cambridge, MA, USA", classification = "C5230 (Digital arithmetic methods); C7310 (Mathematics)", confdate = "20-22 June 1990", conflocation = "White Plains, NY, USA", confsponsor = "ACM", keywords = "Floating-point numbers; Decimal representation; Explicit representation; Rounding accuracy; Fixed-point fractions; Radix-conversion; Conversion process; Free-format output; Free-format conversion algorithm; Fixed-format applications; Garbage digits; Digit positions", language = "English", pubcountry = "USA", thesaurus = "Digital arithmetic; Mathematics computing", } @Book{Feijen:1990:BOB, editor = "W. H. J. Feijen and A. J. M. {van Gasteren} and D. Gries and J. Misra", booktitle = "Beauty is our business: a birthday salute to {Edsger W. Dijkstra}", title = "Beauty is our business: a birthday salute to {Edsger W. Dijkstra}", publisher = pub-SV, address = pub-SV:adr, pages = "xix + 453", year = "1990", ISBN = "0-387-97299-4", LCCN = "QA76 .B326 1990", bibdate = "Thu Mar 24 09:27:40 1994", acknowledgement = ack-nhfb, } @Article{Burger:1996:PFN, author = "Robert G. Burger and R. Kent Dybvig", title = "Printing Floating-Point Numbers Quickly and Accurately", journal = j-SIGPLAN, volume = "31", number = "5", pages = "108--116", month = may, year = "1996", CODEN = "SINODQ", ISSN = "0362-1340", bibdate = "Sun May 02 09:16:12 1999", note = "This paper offers a significantly faster algorithm than that of \cite{Steele:1990:HPF}, together with a correctness proof and an implementation in Scheme. See also \cite{Clinger:1990:HRF,Abbott:1999:ASS}.", acknowledgement = ack-nhfb, } @Book{Chan:1998:JCLb, author = "Patrick Chan and Rosanna Lee", title = "The {Java} Class Libraries: java.applet, java.awt, java.beans", volume = "2", publisher = pub-AW, address = pub-AW:adr, edition = "Second", pages = "1712", year = "1998", ISBN = "0-201-31003-1", LCCN = "QA76.73.J38C47 1998", bibdate = "Wed May 27 07:02:55 1998", bibsource = "http://www.aw.com/", price = "US\$54", URL = "http://cseng.aw.com/bookdetail.qry?ISBN=0-201-31003-1; http://www2.awl.com/cgi-bin/htsearch?restrict=&exclude=&config=htdig&method=boolean&format=builtin%2Dlong&words=Chan%20AND%20Lee&page=2", acknowledgement = ack-nhfb, annote = "See \cite{Chan:1999:JCLb} for vol. 1.", } @TechReport{Kahan:1998:HJFa, author = "W. Kahan and Joseph D. Darcy", title = "How {Java}'s Floating-Point Hurts Everyone Everywhere", type = "Technical Report", institution = "Department of Mathematics and Department of Electrical Engineering and Computer Science, University of California, Berkeley", address = "Berkeley, CA, USA", pages = "80", day = "18", month = jun, year = "1998", bibdate = "Sat Sep 12 18:53:11 1998", URL = "http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf; http://www.cs.berkeley.edu/~wkahan/JAVAhurt.ps", acknowledgement = ack-nhfb, annote = "The authors deliver a biting criticism of Java for its failure to use the 80-bit temporary real format on Intel x86 architectures, failure to use multiply-add instructions when available, and failure to compute float subexpressions in double precision.", } @Book{Chan:1999:JCLb, author = "Patrick Chan and Rosanna Lee and Doug Kramer", title = "The {Java} Class Libraries, Volume 1", publisher = pub-AW, address = pub-AW:adr, edition = "Second", pages = "704", year = "1999", ISBN = "0-201-31002-3", LCCN = "QA76.73.J38 C47 1998", bibdate = "Tue May 11 07:28:09 1999", price = "US\$34.95", acknowledgement = ack-nhfb, annote = "Covers java.io, java.lang., java.math, java.net, java.text, java.util", } @Book{Chan:1999:JCLc, author = "Patrick Chan and Rosanna Lee and Douglas Kramer", title = "The {Java} Class Libraries, Second Edition, Volume 1: Supplement for {Java 2} Platform, Standard Edition, v1.2", publisher = pub-AW, address = pub-AW:adr, pages = "xxix + 1157", year = "1999", ISBN = "0-201-48552-4", LCCN = "QA76.73.J38 C47 1998", bibdate = "Sat May 11 09:29:34 2002", bibsource = "http://www1.fatbrain.com/asp/bookinfo/bookinfo.asp?theisbn=0201485524", price = "US\$34.95", acknowledgement = ack-nhfb, } @Article{Abbott:1999:ASS, author = "P. H. Abbott and D. G. Brush and C. W. {Clark III} and C. J. Crone and J. R. Ehrman and G. W. Ewart and C. A. Goodrich and M. Hack and J. S. Kapernick and B. J. Minchau and W. C. Shepard and R. M. {Smith, Sr.} and R. Tallman and S. Walkowiak and A. Watanabe and W. R. White", title = "Architecture and software support in {IBM S/390 Parallel Enterprise Servers} for {IEEE} Floating-Point arithmetic", journal = j-IBM-JRD, volume = "43", number = "5/6", pages = "723--760", month = "????", year = "1999", CODEN = "IBMJAE", ISSN = "0018-8646", bibdate = "Wed Apr 19 18:58:23 MDT 2000", note = "Besides important history of the development of the S/360 floating-point architecture, this paper has a good description of IBM's algorithm for exact decimal-to-binary conversion, complementing earlier ones \cite{Steele:1990:HPF,Clinger:1990:HRF,Knuth:1990:SPW,Burger:1996:PFN}.", URL = "http://www.research.ibm.com/journal/rd/435/abbott.html", acknowledgement = ack-nhfb, } @Book{Bloch:2001:EJP, author = "Joshua Bloch", title = "Effective {Java}: Programming Language Guide", publisher = pub-AW, address = pub-AW:adr, pages = "xvi + 252", year = "2001", ISBN = "0-201-31005-8", LCCN = "QA76.73.J38 B57 2001", bibdate = "Sat Apr 20 11:10:41 2002", series = "Java series", acknowledgement = ack-nhfb, contents= "1. Introduction -- 2. Creating and destroying objects -- 3. Methods common to all objects -- 4. Classes and interfaces -- 5. Substitutes for C constructs -- 6. Methods -- 7. General programming -- 8. Exceptions -- 9. Threads -- 10. Serialization", keywords = "java (computer program language)", } ------------------------------------------------------------------------ ================================= Introduction to the C/C++ version ================================= This is a substantial update of some old (1987) work documented below to provide a highly-portable C (and C++) translation of the Fortran ELEFUNT packages. At the time the translation from Fortran to C was originally carried out, C was yet to be standardized, double was its only usable floating-point data type, and automated Fortran-to-C translators did not exist. Thus, the translation was done by hand, taking great care to ensure output that is indistinguishable from that produced by the original Fortran code. For this new version, ELEFUNT has been significantly extended in C and C++, and in Fortran, to test the quadruple-precision (C/C++ long double and Fortran REAL*16) elementary functions. To my knowledge, no such version of ELEFUNT has hitherto been available, although computer vendors may well have produced in-house versions for their own testing purposes. [A Java version of the single- and double- precision tests is available.] Although a freely-available, and highly reliable, Fortran-to-C translator, f2c, is now available, I chose to continue the tradition of hand translation of the quadruple-precision Fortran code for two very good reasons: * f2c does not recognize quadruple-precision Fortran, and thus could not do the job (though the commercial Cobalt Blue translator might), and * f2c translates Fortran I/O statements into calls to a separate library which must be ported and be available, and which substantially obscure the code. The hand translation ensures that Fortran WRITE statements are converted to more readable C printf() function calls, and that the numerous Fortran goto statements which confuse control flow have been almost entirely banished (just one remains in each of the three machar*() functions). ------------------------------------------------------------------------ C Version of the Code & Waite ELEFUNT Elementary Function Test Package [15-Jun-1987] This C version of the ELEFUNT test package was translated by Ken Stoner (GU.STONER@SCIENCE.UTAH.EDU) and Nelson H.F. Beebe (BEEBE@SCIENCE.UTAH.EDU) at the Center for Scientific Computing, Department of Mathematics, University of Utah. The translation was carried out by converting the original FORTRAN code to Ratfor automatically with the Unix struct utility, then hand editing the Ratfor to C, which resemble one another. Considerable care has been taken to match the output format of the two versions, so that after the characters +-0123456789 have been converted to blanks, the output listings should substantially agree. One error was corrected in FORMAT 1030 in TPOWER--a missing right parenthesis. The FORTRAN version has some inconsistencies in the number of blank lines used for spacing the output; we have opted in favor of uniformity in the C version. C is problematic for numerical work on several grounds: * Parentheses in expressions cannot be used to enforce evaluation order; temporary variables must be introduced. This was particularly a problem in machar.c. * C has float and double data types, but an implementation is free to implement these in the same precision (PCC-20 uses only single precision); the run-time library is written only in type double. * The behavior of library functions with respect to out-of-range arguments, or arguments which would result in substantial accuracy loss, is not standardized. Most C run-time libraries simply set the global error value "errno" to a non-zero value and return an arbitrary function result. Code to test errno has been added to the test programs. * The behavior of floating-point arithmetic in response to underflow or overflow is not well-defined. In addition, machines with IEEE arithmetic (which is provided by most newer architectures) place additional demands on numerical software because they have computational units of greater precision than is stored in memory. For example, several implementations compute with 80-bit extended precision, but store 32-bit or 64-bit values in memory. Code in machar is particularly sensitive to this, and it has been necessary to force memory stores in intermediate expressions by calling a function store(&memval). Since the address of a memory location is passed to store(), that location can potentially be modified, and the caller of store() must then reload the memory value upon return, rather than using a value that might exist in a higher-precision register. The C version has been written using type "float"; the Makefile's for it provide an implicit "#define float double" for those systems in which the two precisions are implemented differently, so that the tests are carried out at the precision of the run-time library.