›››› FP65 - Floating-Point Math for CC65› › Copyright 1992 by Duane Tribe.› › › OVERVIEW› › FP65 provides C functions that manipulate floating-point (FP) numbers› using the code and data format of the Atari ROMs.› › FP65 is similar to the ACE-C runtime package because neither CC65 nor› ACE-C directly supports FP data. The speed of the functions is› comparable to BASIC because both Atari BASIC and FP65 use the same ROM› routines to perform the FP math.› › The FP65 functions are in the object library file C0F1.OLB which› replaces the file C.OLB from the CC65 distribution. The functions› are:› fcmp Compare two floats› fcpy Copy floats› atof, ftoa ASCII-float conversion› utof, ftou Unsigned integer-float conversion› itof, ftoi Signed integer-float conversion› fadd, fsub Add, subtract floats› fmul, fdiv Multiply, divide floats› exp, exp10 Raise e (2.71828...), 10.0 to a power› log, log10 Find natural (base e), common (base 10) logarithm› pow Raise a float to a power› sqrt Find square root of a float› hypot Find hyponenuse given length of two sides› sin, cos Find sine, cosine of an angle› floor,ceil Find nearest whole float equal or less, greater› frac Find fractional portion of a float› fabs Find absolute value of a float› poly Calculate float polynomial› fperror Control error behavior› › The FP65 functions in the file C0F1.OLB and the rest of the FP65› archive are copyright 1992 by Duane Tribe. See the file README for› details. The non-FP65 functions in C0F1.OLB are from the CC65› distribution's C.OLB file and are "copyleft" by John R. Dunning. › Refer to the file COPYLEFT.JRD in the CC65 distributions for details.› › › USING FLOATING-POINT MATH› › First, do not use FP math unless it is required. Not only is it less› convenient than integer math, it is also much slower. FP65 provides› functions for algorithms where only FP math will do.› › Like all other C compilers currently available for the 8-bit Atari,› CC65 does not directly support floats. Instead of the usual› › float fpvar; /* not in CC65 */› › storage for FP variables is declared as a six-byte character array›››› page 1/10››› FP65 version 1.0, 1992 Using FP Math›››› › char fpvar[6];› › Also, you cannot directly use FP constants such as› › f = 1.2345; /* not in CC65 */› › The FP constant 1.2345 must be converted to the internal six-byte› format. This can be done indirectly via› › atof(f, "1.2345");› › or directly via a C declaration such as› › char f[6] = { 0x40, 0x01, 0x23, 0x45, 0x00, 0x00 };› › The latter version is faster (the compiler does all the work), but› cannot be repeated. Use the supplied program EXPOSE.COM to generate› the values.› › Common FP operations, such as› › f = a + b; /* not in CC65 */› › are done via function calls. In this instance,› › fadd(f, a, b);› › is used instead. Complex expressions must be broken down to the› individual operations, and storage provided for all of the› intermediate values. For example, the C statement› › f = (1.0 / a) + (2.0 * b); /* not in CC65 */› › would be implemented via› › fdiv(f, M_1, a);› fmul(temp, M_2, b);› fadd(f, f, temp);› › Due to the nature of the ROM FP format, the sign of an FP value can be› manipulated via C bitwise operations:› › *f /* true if f != 0.0 */› › *f & 0x80 /* true if f < 0.0 */› › *f &= 0x7F; /* make f positive */› › *f |= 0x80; /* make f negative */› › *f ^= 0x80; /* invert sign of f */› › When using this trick, be sure to include comments that indicate your› intent.› ›››› page 2/10››› FP65 version 1.0, 1992 Using the FP65 Package›››› › USING THE FP65 PACKAGE› › First, include the file MATH.H into your C program. Then, link the› program with the C0F1.OLB file instead of the usual C.OLB. For› example, here is a program called SUM.C that will print the sum of two› numbers on the SpartaDOS or DOS-XL command line:› › #include "stdio.h"› #include "math.h"› › main (argc, argv)› int argc;› char *argv[];› {› char buf[20];› char f1[6], f2[6];› › atof(f1, argv[1]);› atof(f2, argv[2]);› › fadd(f1, f1, f2);› › printf("%s + %s = ", argv[1], argv[2]);› fputs(ftoa(buf, f1), stdout);› fputc('\n', stdout);› }› › Also needed is the SUM.LNK file:› › D:RUNTIME.OBJ› D:SUM.OBJ› D:C0F1.OLB› › This assumes all the files are on the same disk and in the same› directory. Then, issue the commands:› › CC65 SUM.C› RA65 SUM.M65› LN65 -O SUM.COM @SUM.LNK› › › FLOATING-POINT CONSTANTS› › FP65 provides nine FP values already in the six-byte ROM format. Use› the names as you would any FP variable, except never assign a value to› them. They are› M_0 0.0 zero› M_1 1.0 one› M_2 2.0 two› M_10 10.0 ten› M_N1 -1.0 negative one› M_P5 0.5 point five› M_E 2.718281828 e› M_PI 3.141592654 pi› M_2PI 6.283185308 2*pi›››› page 3/10››› FP65 version 1.0, 1992 FP Constants›››› › These constants are declared in the include file MATH.H. Other› less-often used standard C constants are provided as C initialized› declarations:› M_LOG2E 1.44269504 log2(e)› M_LOG10E 0.4342944819 log10(e)› M_LN2 0.6931471806 log(2)› M_LN10 2.30258509 log(10.0)› M_PI_2 1.57079632 pi/2› M_PI_4 0.7853981634 pi/4› M_1_PI 0.3183098862 1/pi› M_2_PI 0.6366197724 2/pi› M_2_SQRTPI 1.128379167 2/sqrt(pi)› M_SQRT2 1.41421356 sqrt(2)› M_SQRT1_2 0.7071067812 sqrt(1/2)› M_MIN 1E-98 Minimum value› M_MAX 9.999999999E99 Maximum value› M_EPSILON 1E-9 Accuracy limit› › To activate these extra constants, define the symbol FP65_CDEF before› including MATH.H:› › #define FP65_CDEF› #include "math.h"› › See the file MATH.H for further details.› › › ERROR CHECKING› › Errors are detected where possible. The default action on an error is› to print a message and exit to DOS. You can also have FP65 ignore the› error, or you can handle the error yourself. See the fperror› description below.› › If the error is detectable before the call to the OS ROM routine, then› a "domain error" is generated. If the ROM routine returns an error› condition, a "range error" is generated.› › › PARAMETERS AND ACE-C› › Although many FP65 functions look just like ACE-C functions, their use› is slightly different. The result value is always stored via the› first parameter. This is based on how the expression would look in a› true C float expression. For example, the C float expression› › a = b + c; /* not in CC65 */› › implemented in ACE-C as› › fadd(b, c, a); /* ACE-C, not FP65 */› › is implemented in FP65 as› › fadd(a, b, c);›››› page 4/10››› FP65 version 1.0, 1992 Parameters and ACE-C›››› › Functions that have an FP result return from their name the the value› of the first parameter, the pointer to where the resulting value is› stored. This return value is for convenience only and can be› ignored.› › Two functions available in ACE-C have C-style names in FP65: log10› (ACE-C calls it "clog") and pow (ACE-C calls it "exp"). Also, ACE-C› has two functions "ftoi" and "itof" which really deal only in unsigned› integers; the corresponding FP65 functions are ftou and utof.› › › CONVERSION FUNCTIONS› › atof› › char *atof (fpn, str)› char fpn[6], str[];› › Converts C-style ASCII string at str to FP number at fpn. Stops› converting at the first non-FP character. Note that when using› exponential notation the "E" must be in upper case. Returns fpn.› › ftoa› › char *ftoa (str, fpn)› char str[], fpn[6];› › Converts FP number at fpn to ASCII in buffer pointed to by str. › Required to print out a number. Note that 1x10^8 will convert to the› string "1E8", but 1x10^9 will convert to the string "1.0E9". The› buffer must be big enough to hold the number and terminating NULL, at› least 17 bytes. Returns str.› › utof› › char *utof (fpn, i)› char fpn[6];› int i;› › Convert unsigned integer i [0..65535] to FP number at fpn. Returns› fpn.› › ftou› › int ftou (fpn)› char fpn[6];› › Return unsigned integer [0..65535], converted from the FP number fpn,› rounded off by the ROM routine to the nearest integer.› ››››››››› page 5/10››› FP65 version 1.0, 1992 Conversion Functions›››› itof› › char *itof (fpn, i)› char fpn[6];› int i;› › Convert signed integer i [-16385..16384] to FP number at fpn. Returns› fpn.› › ftoi› › int ftoi (fpn)› char fpn[6];› › Return signed integer [-16385..16384] converted from FP number fpn,› rounded off by the ROM routine to the nearest integer.› › › ARITHMETIC FUNCTIONS› › The names for these functions and the "True-C" notation should make› them self explanatory. Their arguments may be repeated, i.e.› › fadd(a, a, b); /* a += b; */› › fadd› › char *fadd (dst, f1, f2)› char dst[6], f1[6], f2[6];› › Floating-point addition. True-C: dst = f1 + f2; Returns dst.› › fsub› › char *fsub (dst, f1, f2)› char dst[6], f1[6], f2[6];› › Floating-point subtraction. True-C: dst = f1 - f2; Returns dst.› › fmul› › fmul (dst, f1, f2)› char dst[6], f1[6], f2[6];› › Floating-point multiplication. True-C: dst = f1 * f2; Returns dst.› › fdiv› › char *fdiv (dst, f1, f2)› char dst[6], f1[6], f2[6];› › Floating-point division. True-C: dst = f1 / f2; Returns dst.› › ›››››› page 6/10››› FP65 version 1.0, 1992 Logarithm and Exponentiation›››› LOGARITHM AND EXPONENTIATION› › If you have a choice between using the base e functions (exp and log)› and the base 10 functions (exp10 and log10), use the base 10› functions. They are faster.› › exp› › char *exp (dst, fpn)› char dst[6], fpn[6];› › Calculate e raised to the fpn power, storing the result in dst. › Returns dst.› › exp10› › char *exp10 (dst, fpn)› char dst[6], fpn[6];› › Calculate 10.0 raised to the fpn power, storing the result in dst. › Returns dst.› › log› › char *log (dst, fpn)› char dst[6], fpn[6];› › Calculate the natural (base e) logarithm of fpn, storing the result in› dst. Returns dst.› › log10› › char *log10 (dst, fpn)› char dst[6], fpn[6];› › Calculate the common (base 10) logarithm of fpn, storing the result in› dst. Returns dst.› › pow› › char *pow (dst, x, y)› char dst[6], x[6], y[6];› › Find x raised to the y power, storing the result in dst. Only› generates domain error if a complex number would result. Returns› dst.› › sqrt› › char *sqrt (dst, fpn)› char dst[6], fpn[6];› › Find square root of fpn, storing the result in dst. Returns dst.› ›››››› page 7/10››› FP65 version 1.0, 1992 Logarithm and Exponentiation›››› hypot› › char *hypot (dst, f1, f2)› char dst[6], f1[6], f2[6];› › Calculates the length of the hypotenuse of a right triangle with f1› and f2 as the two other sides, storing the result in dst. Written to› minimize range (overflow) errors, so may be slower than doing it by› hand. Returns dst.› › › TRIGONOMETRY› › These functions work only in radians.› › sin› › char *sin (dst, fpn)› char dst[6], fpn[6];› › Computes the sine of fpn and stores the result at dst. Returns dst.› › cos› › char *cos (dst, fpn)› char dst[6], fpn[6];› › Computes the cosine of fpn and stores the result at dst. Returns› dst.› › › INTEGER PORTION› › The first two functions have their proper C names that may be› unfamiliar. Think of the real number line as running vertical in a› multi-story building, with the integer numbers marking the floors (and› ceilings). Since these functions do not use the ROM integer-FP› routines, they are valid for any size or sign and do not round up or› down.› › floor› › char *floor (dst, fpn)› char dst[6], fpn[6];› › Finds the largest whole FP number that is less than or equal to fpn› and stores it at dst. (Drop the number down to the floor.) Returns› dst.› › ceil› › char *ceil (dst, fpn)› char dst[6], fpn[6];› › Finds the smallest whole FP number that is greater than or equal to› fpn and stores it at dst. (Raise the number up to the ceiling.) ›››› page 8/10››› FP65 version 1.0, 1992 Integer Portion›››› Returns dst.› › frac› › char *frac (dst, fpn)› char dst[6], fpn[6];› › Finds the fractional portion of fpn and stores it at dst. The value› returned is always positive. Returns dst.› › › GENERAL FP FUNCTIONS› › fcpy› › char *fcpy (dst, fpn);› char dst[6], fpn[6];› › Copy FP number from fpn to dst. Returns dst.› › fabs› › char *fabs (dst, fpn);› char dst[6], fpn[6];› › Store absolute value of fpn in dst. Returns dst. Can be used as› › fabs(f, f);› › to make f positive. This can be accomplished in C via bitwise› operators, see "Using Floating-Point Math" above. › › fcmp› › int fcmp (f1, f2)› char f1[6], f2[6];› › Compare the two FP numbers f1 and f2. Returns integer giving the› result of the comparison, as with strcmp:› › Negative: f1 < f2› Zero: f1 == f2› Positive: f1 > f2› › The magnitude of the result, other than zero, is meaningless.› › poly› › char *poly (dst, x, coef, n)› char dst[6], x[6], coef[6][];› int n;› › Calculates the value of the n-degree polynomial at x and stores the› result at dst. The coeficients are passed in the array coef in› descending order. Returns dst. This routine is very suceptable to› overflow errors. It works best with small, fractional coeficients. ›››› page 9/10››› FP65 version 1.0, 1992 General FP Functions›››› See the file POLYEX.C for an example.› › fperror› › fperror (matherr)› int (*matherr)();› › Controls how errors are handled. The value of matherr is either:› › 1. 0 ($0000) When an error occurs, the program will print a message› indicating the error and exit to DOS. This is the default.› 2. -1 ($FFFF) All FP errors will be ignored. The offending function› will limp along the best it can, with unpredictable results.› 3. A pointer to a C function that will be called to handle the error.› The function will be passed one argument, a pointer to the› exception structure› › struct exception› {› int fp_type;› int fp_name;› };› › containing data about the error.› › The error-handling function will take the place of the offending› FP65 function, sending its integer return value to the caller of› the offending FP65 function.› › In struct exception, the value of fp_type is either› 0 domain error› 1 range error› › The value of fp_name is one of› 0 atof 7 fsub 14 fcpy 21 poly 28 atan › 1 ftoa 8 fmul 15 fabs 22 hypot 29 fmod › 2 utof 9 fdiv 16 pow 23 sin 30 frac › 3 ftou 10 exp 17 sqrt 24 cos 31 trunc› 4 itof 11 exp10 18 fcmp 25 tan › 5 ftoi 12 log 19 floor 26 asin › 6 fadd 13 log10 20 ceil 27 acos › › Function codes 25 through 29 and 31 are reserved for future expansion.› See the file ERROR.C for an example of fperror in use.› ››››››››››››››› page 10/10›››