zsh extended for IEEE 754 arithmetic [zsh-4.1.1-nonstop-fp] 27 February 2004 ====== AUTHOR ====== 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 (Internet) WWW URL: http://www.math.utah.edu/~beebe Telephone: +1 801 581 5254 FAX: +1 801 581 4148 =========== BUG REPORTS =========== All floating-point problems arising from the extensions should be directed to the extension author at any of the email addresses listed above. Please include [zsh-4.1.1-nonstop-fp] in the Subject: line of your email to facilitate processing. All other zsh problems should be reported to the zsh developers at the addresses described in the section ``Zsh Maintenance and Bug Reports'' of the companion README file. ============ INTRODUCTION ============ The zsh distribution labeled zsh-4.1.1-nonstop-fp is an extension of zsh-4.1.1 that provides full support for IEEE 754 arithmetic [formally, ANSI/IEEE 754-1985, Standard for Binary Floating-Point Arithmetic, August 1985]. It provides nonstop floating-point computation, bringing the arithmetic behavior into agreement with the intent of that Standard, and with the behavior of most other programming languages suitable for numerical computation, including Fortran, C, C++, and Java. Although IEEE 754 was not adopted until mid-1985, published drafts were available several years earlier. The first implementation was the Intel 8087 on which the original IBM PC was based in 1981. Since then, Intel IA-32 (formerly x86), i860, i960 and IA-64, Convex, HP/Compaq/DEC Alpha, HP PA-RISC, IBM Power and PowerPC, Motorola 68K and 88K, SGI MIPS, Sun SPARC, and most other CPUs (even on embedded systems) with floating-point point support adhere to at least part of the IEEE 754 specification. All Cray supercomputers manufactured since the early 1990s have used IEEE 754 arithmetic. The only non-IEEE-754 desktop (and larger) CPUs built since the mid-1980s have been the Compaq/DEC VAX (now obsolete), and the venerable IBM S/360 architecture first introduced in 1964. However, in 1998, IBM added the G5 processor boards on System/390 (Z series) with full IEEE 754 support (including 128-bit quadruple precision in hardware), and GNU/Linux on that system uses only IEEE 754 arithmetic (even though the S/360 arithmetic is available, the GNU/Linux compilers and library don't support it). In addition to CPUs, the Java Virtual Machine specification mandates a subset of IEEE 754 arithmetic. Thus, there is strong reason to have IEEE 754 floating-point arithmetic properly supported in all programming languages. The usual floating-point number representation as a sign, an exponent (of 2, for IEEE 754), and normalized significand fpnum = (-1)**s * 2**(exponent) * significand gives numbers with finite range and precision. IEEE 754 provides other important features: * +Infinity and -Infinity: generated when the magnitude is too large to represent (e.g. 1.0e+10000), or 1.0 / 0.0. Infinities propagate in binary operations and unary function evaluations, but can disappear in division: (any-finite)/Infinity is 0.0. * NaN (Not a Number): generated when the result is not representable as a real value, such as 0.0 / 0.0, Infinity - Infinity, sqrt(-1), ... NaNs propagate in binary operations and unary function evaluations, and are the only value for which (x != x) is true. * Subnormals: generated when the underflow limit is reached, and the normalization constraint is lifted, so that smaller values are represented with reduced precision. * Signed zeros: -0.0 compares equal to +0.0, but is generated by 0.0 / (negative value) or sqrt(-0.0). Before this version, zsh behaved like this: % zsh-4.1.1 $ echo $ZSH_VERSION 4.1.1 $ zmodload zsh/mathfunc $ x=$(( 1.0 / 0.0 )) zsh: division by zero $ x=$(( log(-1.0) )) zsh: math: argument to log out of range and ksh93 like this: % /usr/local/bin/ksh Type Ctl-V Version M 1993-12-28 o+ $ x=$(( 1.0 / 0.0 )) ksh: 1.0 / 0.0 : divide by zero $ x=$(( log(-1.0) )) ksh: log: domain exception and ksh88 like this: % /bin/ksh Type Ctl-V Version M-11/16/88i $ x=$(( 1.0 / 0.0 )) /bin/ksh: 1.0 / 0.0 : divide by zero $ x=$(( log(-1.0) )) /bin/ksh: log(-1.0) : unknown function Aborting on overflow and invalid arguments is considered antisocial behavior in IEEE 754 arithmetic: that is why it supports Infinity and NaN, for nonstop computing. In the new version of zsh, here is what happens: % zsh $ echo $ZSH_VERSION 4.1.1-nonstop-fp $ x=$(( 1.0 / 0.0 )) $ echo $x Inf $ printf "%g\n" $x Inf $ x=$(( 0.0 / 0.0 )) $ echo $x NaN $ printf "%g\n" $x NaN $ echo $(( log(-1.0) )) -Inf $ echo $(( atanh(2.0) )) NaN The test script ksh93-test.sh included in the distributed can be used to exercise many of the features of floating-point arithmetic, including determination of the machine precision, overflow limit, underflow limit, whether subnormals are supported, whether signed zeros are correctly handled (they are not in many C runtime libraries, but recent GNU glibc works correctly), and sampling of the large elementary floating-point function repertoire offered by ksh and zsh. ============ CODE CHANGES ============ The zsh-4.1.1 code (84 source files, 100,273 lines of code) is very cleanly designed, and the changes to provide nonstop operation were confined to a small number of places. The changes are entirely under the control of a single preprocessor macro: NONSTOP_FP. If that macro is not defined at compile time, the code that is compiled is effectively identical to that in the zsh-4.1.1 release: you can easily do that after running configure by make DEFS=-DHAVE_CONFIG_H instead of make For numbers that zsh itself converts, the standard representations of Infinity and NaN are Inf and NaN. However, printf may produce different output that zsh cannot interpret: compare these results on an SGI IRIX system: $ x=$((0.0 / 0.0)) $ echo $x NaN $ printf "%g\n" $x nan0x80000000 $ x=$(( 1.0 / 0.0 )) $ echo $x Inf $ printf "%g\n" $x inf Here is a summary of the changes: Config/defs.mk.in Augment DEFS with -DNONSTOP_FP. Config/version.mk Update VERSION and VERSION_DATE. Doc/version.yo [Automatically generated.] README.NONSTOP-FP This file. Src/init.c Add flush_to_zero() function to provide support for subnormals on SGI IRIX. Src/Modules/mathfunc.c Disable tests for elementary-function argument ranges. Src/math.c Include . Add functions isinf(), isnan() and store(), if the first two are not provided in the C runtime library (most systems have them, and they are part of 1999 ISO Standard C). store() is a helper function for isnan(). Add code block in zzlex() to recognize tokens Inf and NaN. Disable zero-divisor test in notzero(). Src/params.c Include and provide prototypes of functions isinf() and isnan() [they are only macros in C99, but functions, when available, in most current C89 implementations]. config.guess New version from GNU maintainers. [The 4.1.1 fails on Compaq Alpha OSF/1 5.1.] config.h.in [Automatically generated by autoconf] config.sub New version from GNU maintainers. configure [Automatically generated by autoconf] stamp-h.in [Automatically generated by autoconf] zshconfig.ac Add checks for isinf() and isnan() library functions, and also for get_fpc_csr() [needed on SGI IRIX to get support for subnormals.] ================ TESTED PLATFORMS ================ This release of zsh-4.1.1-nonstop-fp has been successfully built and tested in these compilation environments: Apple PowerPC G3 267MHz GNU/Linux 2.4.19-4a (Yellow Dog Linux release 2.3 (Dayton)) gcc Apple PowerPC G4 1.4GHz Darwin 7.2.0 (MacOS 10.3.2 (7D26)) gcc Compaq Alpha Sierra OSF/1 5.1 cc, gcc Compaq/DEC Alpha OSF/1 4.0F cc, gcc DEC Alpha GNU/Linux 2.2.19-6.2.1 (Red Hat 6.2) gcc HP rx2470 PA-RISC 8700 HP-UX 11i 11.11 cc HP rx2600 Itanium-2 HP-UX 11i 11.22 cc IBM PowerPC AIX 4.2 c89 Intel Itanium-2 GNU/Linux Red Hat Linux Advanced Server release 2.1AS (Derry) gcc, icc Intel Pentium II FreeBSD 4.4-RELEASE #0 cc Intel Pentium III FreeBSD 4.9 gcc Intel Pentium III FreeBSD 5.0 cc, gcc Intel Pentium III GNU/Linux 2.4.18-26.8.0smp (Red Hat 8.0 (Psyche)) gcc, icc Intel Pentium III NetBSD 1.6 cc Intel Pentium III OpenBSD 3.2 cc Intel Pentium III Solaris 9 x86 gcc SGI Origin 200 IRIX 6.5 gcc Sun SPARC GNU/Linux 2.2.19-6.2.1 (Red Hat 6.2) gcc Sun SPARC Solaris 2.7 cc, gcc Sun SPARC Solaris 2.8 cc, gcc Sun SPARC Solaris 2.9 cc, gcc In most cases, the gcc version is 3.3.x, but some systems have only 2.95 or 2.96. The Intel icc compiler versions are 8.0. On some systems, notably Alpha ones, extra compilation options are needed to get IEEE 754 nonstop behavior: -ieee for native cc, and -mieee for gcc. The two OSF/1 builds do not create shared-object libraries, so the dynamic module feature of zsh needed to get the elementary-function library loaded is not available. Otherwise, the floating-point arithmetic behaves as IEEE 754 intended. zsh cannot be compiled by C++ compilers; there are numerous instances of missing typecasts from void*, and use of the C++ reserved name "new" as a variable.