123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- [Main]
- Title=Using Floating Point Arithmetic
- [Top]
- If you have used earlier releases of TIGCC (prior to 0.9), you probably know that the use of floating
- point values and functions was possible, but only using some very awkward syntax, which caused a lot of
- headaches and nightmares. The TIGCC team (mostly
- <A HREF="mailto:SebastianR@gmx.de">Sebastian Reichelt</A> and
- <A HREF="mailto:zjuric@utic.net.ba">Zeljko Juric</A>) spent a lot
- of time and effort implementing native (ANSI) floats in TIGCC. And the results are now available:
- you can use regular floating point numbers and values now, as in all regular C compilers! This means
- that:
- <UL>
- <LI>
- You can now use the standard ANSI types <CODE>float</CODE>, <CODE>double</CODE> and
- <CODE>long double</CODE> without any trouble (in fact, these three types are the same,
- there is no difference between them). The old-style type <A HREF="$$LINK(timath.h/ti_float)">ti_float</A>
- still exists due to compatibility reasons, but now it is the same as <CODE>float</CODE>.
- </LI>
- </UL>
- <UL>
- <LI>
- You can now use "standard" floating point constants (like 2.854). So, the following is now valid:
- <PRE>float a, b, c;
- a = 2.854;
- b = 7;
- c = 1.5e-7;
- </PRE>
- In other words, no more ugly <A HREF="$$LINK(timath.h/M_FLT)">FLT</A> and
- <A HREF="$$LINK(timath.h/M_FEXP)">FEXP</A> macros! They still exist due to compatibility reasons,
- but their usage is very deprecated now.
- </LI>
- </UL>
- <UL>
- <LI>
- You can now use standard arithmetic ('+', '-', '*', '/) and comparison ('<', '>',
- '<=', '>=', '==' and '!=') operators with floating point values. There is no need any more
- for the use of awkward functions like <A HREF="$$LINK(timath.h/fadd)">fadd</A>,
- <A HREF="$$LINK(timath.h/fcmp)">fcmp</A> etc. So statements like these are now accepted:
- <PRE>p = (q + 3.15) / (q - r);
- x1 = (-b + sqrt (b * b - 4 * a * c)) / (2 * a);
- if (p < 3.0) q += 1e-3;
- </PRE>
- This feature is probably the best present for TIGCC users...
- </LI>
- </UL>
- <UL>
- <LI>
- You can use all floating point functions (like <A HREF="$$LINK(timath.h/sqrt)">sqrt</A>,
- <A HREF="$$LINK(timath.h/sin)">sin</A> etc.) as usual. In this release, a standard ANSI
- math library <A HREF="$$LINK(math.h/)">math.h</A> is implemented, which contains nearly all
- functions proposed by ANSI C, with some extensions. The old
- <A HREF="$$LINK(timath.h/)">timath.h</A> library file still exists due to compatibility reasons,
- and it contains more functions than <A HREF="$$LINK(math.h/)">math.h</A>, because it contains
- some functions for making compatibility with older programs, and some functions which are
- internally related to the TIOS. Anyway, you can do calculations like these:
- <PRE>a = sin (b);
- b = exp (1);
- c = log (3.19);
- a = sqrt (b + c) * sinh (a / 2.);
- </PRE>
- As you can see from the second example, automatic promotion from integer constants to
- the floating point is also implemented.</LI>
- </UL>
- <UL>
- <LI>
- Integer types are now automatically promoted to floating point values when necessary, as
- proposed in ANSI C. This means that the following constructions are valid, assuming that
- <CODE>'n'</CODE> is a variable of integer (short, long, signed, unsigned) type:
- <PRE>a = n;
- b = sqrt (n);
- c = b + n;
- </PRE>
- You can also explicitely cast an integer value to a floating point one:
- <PRE>a = (float)n;
- </PRE>
- The function <A HREF="$$LINK(timath.h/flt)">flt</A> which performs the promotion explicitely
- still exists, due to compatibility reasons.
- </LI>
- </UL>
- <UL>
- <LI>
- Floating point types are automatically truncated to integers when the program
- expects an integer value (for example, when a floating point variable is assigned to an integer
- variable), as proposed in ANSI C. This means that you can write
- <PRE>n = a;
- </PRE>
- where <CODE>'n'</CODE> is an integer, and <CODE>'a'</CODE> is a float, although it is better
- to express your wish more explicitely using type cast as
- <PRE>n = (int)a;</PRE>
- The function <A HREF="$$LINK(timath.h/trunc)">trunc</A> which performs the
- truncation explicitely still exists due to compatibility reasons.
- </LI>
- </UL>
- <UL>
- <LI>
- You can use <A HREF="$$LINK(stdio.h/printf)">printf</A> and similar
- functions to print floating point values, using the format specifiers <CODE>%f</CODE>,
- <CODE>%e</CODE> and <CODE>%g</CODE>, as defined in ANSI C. So, the following is
- completely legal:
- <PRE>printf ("sin(%f)=%f", a, sin(a));
- printf ("%f", 3.14);</PRE>
- Note that the second statement was not valid prior to release 0.9 of TIGCC!
- </LI>
- </UL>
- <UL>
- <LI>
- To accept a floating point value from the keyboard, first accept it as a string (using
- <A HREF="$$LINK(stdio.h/gets)">gets</A>, some user-written input routine, or
- functions from <A HREF="$$LINK(dialogs.h/)">dialogs.h</A>), then
- convert the string to a floating point value using the <A HREF="$$LINK(timath.h/atof)">atof</A>
- (ascii-to-float) function. To get a floating point argument passed from TI-Basic to the
- program, use the <A HREF="$$LINK(args.h/GetFloatArg)">GetFloatArg</A> function.
- </LI>
- </UL>
- As you can see, the usage of floats with TIGCC is now essentially the same as in all other C
- compilers. See the description of the <A HREF="$$LINK(math.h/)">math.h</A> and
- <A HREF="$$LINK(timath.h/)">timath.h</A> header files for more info. However, floating point
- support in TIGCC is not perfect yet. That's why there are still some limitations
- in the use of floating point values (fortunately, they are not serious):
- <UL>
- <LI>
- The promotion of double long integers (<A HREF="$$INFOLINK(gnuexts/SEC72)">long long</A> types) to
- floating point values, and truncation of floating point values to longlongs are not implemented
- yet. If you try to do this (which is not very likely), you will get an "undefined reference"
- error during the linking stage.
- </LI>
- </UL>
- As an example of usage of floating point values and functions, the program given below
- (called "Float Test") reads coefficients of a quadratic equation from the keyboard, then
- calculates and displays the solutions of the equation (including complex ones):
- $$EXAMPLE(Float Test.c)
- See the description of the included header files for more info about the functions used.
- <BR><BR>
- As already mentioned above, the new floating point support is implemented without
- losing compatibility with programs written with releases of TIGCC before 0.9
- (more precise, the degree of compatibility is about 95%; read further to see possible
- reasons of incompatibility). So, the quadratic equation solver given below, which
- is written using old methods (prior to TIGCC 0.9), will still work with a new compiler.
- Compare this (old-style) code with the previous (new-style) one to see how much clearer
- the new-style code is...
- <PRE>#define SAVE_SCREEN
- #include <stdio.h>
- #include <timath.h>
- #include <string.h>
- #include <kbd.h>
- int _ti89, _ti92plus;
- void _main (void)
- {
- ti_float a, b, c, d;
- char buffer[200];
- clrscr ();
- puts ("a=");
- a = atof (gets (buffer));
- puts ("b=");
- b = atof (gets (buffer));
- puts ("c=");
- c = atof (gets (buffer));
- if (is_nan (a) || is_nan (b) || is_nan (c)) return;
- d = fsub (fmul (b, b), fmul (FLT (4), fmul (a, c)));
- if (fcmp (d, ZERO) >= 0)
- {
- ti_float x1, x2;
- x1 = fdiv (fadd (fneg (b), sqrt (d)), fadd (a, a));
- x2 = fdiv (fsub (fneg (b), sqrt (d)), fadd (a, a));
- printf ("\nx1=%f\nx2=%f", x1, x2);
- }
- else
- {
- ti_float re, im;
- re = fdiv (fneg (b), fadd (a,a));
- im = fabs (fdiv (sqrt (fneg (d)), fadd(a, a)));
- printf ("\nx1=%f-%f*i\nx2=%f+%f*i", re, im, re, im);
- }
- ngetchx();
- }
- </PRE>
- The possible reasons which may cause incompatibility (very unlikely) with programs written
- with older versions of TIGCC (prior to 0.9) are:
- <UL>
- <LI>
- The types <A HREF="$$LINK(timath.h/ti_float)">ti_float</A> and <A HREF="$$LINK(timath.h/bcd)">bcd</A>
- are not the same any more.
- <CODE>ti_float</CODE> is now equal to ANSI type <CODE>float</CODE>, but
- <CODE>bcd</CODE> is still a structure. If your program uses the
- <CODE>bcd</CODE> type (not very likely), you should probably change it to
- <CODE>float</CODE> to make the program work, because functions which expect a
- <CODE>float</CODE> type will not accept a structured type. Two macros called
- <A HREF="$$LINK(timath.h/float_to_bcd)">float_to_bcd</A> and
- <A HREF="$$LINK(timath.h/bcd_to_float)">bcd_to_float</A> have been introduced to provide more general
- conversion if necessary.
- </LI>
- </UL>
- <UL>
- <LI>
- Functions <A HREF="$$LINK(timath.h/fadd)">fadd</A>, <A HREF="$$LINK(timath.h/fsub)">fsub</A>,
- <A HREF="$$LINK(timath.h/fmul)">fmul</A>, <A HREF="$$LINK(timath.h/fdiv)">fdiv</A>,
- <A HREF="$$LINK(timath.h/fneg)">fneg</A>, <A HREF="$$LINK(timath.h/fcmp)">fcmp</A>,
- <A HREF="$$LINK(timath.h/flt)">flt</A> and <A HREF="$$LINK(timath.h/trunc)">trunc</A> are not
- absolutely equal to functions
- <A HREF="$$LINK(timath.h/bcdadd)">bcdadd</A>, <A HREF="$$LINK(timath.h/bcdsub)">bcdsub</A>,
- <A HREF="$$LINK(timath.h/bcdmul)">bcdmul</A>, <A HREF="$$LINK(timath.h/bcddiv)">bcddiv</A>,
- <A HREF="$$LINK(timath.h/bcdneg)">bcdneg</A>, <A HREF="$$LINK(timath.h/bcdcmp)">bcdcmp</A>,
- <A HREF="$$LINK(timath.h/bcdbcd)">bcdbcd</A> and <A HREF="$$LINK(timath.h/bcdlong)">bcdlong</A> any more.
- The first group of functions now works with the ordinary <CODE>float</CODE> type (and they
- will continue to work with <A HREF="$$LINK(timath.h/ti_float)">ti_float</A>), but the second
- group now only works with <A HREF="$$LINK(timath.h/bcd)">bcd</A> structures. So, if you used
- <CODE>bcdadd</CODE> etc. in your program (not very likely), you should
- probably change it to <CODE>fadd</CODE> etc. to make the program work.
- </LI>
- </UL>
- <UL>
- <LI>
- Suppose that your old program uses the <A HREF="$$LINK(timath.h/ti_float)">ti_float</A> type with
- direct access to its internal fields (not very likely), like in the following example:
- <PRE>ti_float a;
- a.exponent = 0x4003;
- a.mantissa = 0x3284300000000000;
- </PRE>
- Then the program will not work with the new compiler, because <CODE>ti_float</CODE> is not a
- structure any more. Using a new macro <A HREF="$$LINK(timath.h/bcd_var)">bcd_var</A> you can easily
- get your program to work. All you need to do is to re-express the above statements as
- <PRE>ti_float a;
- bcd_var(a).exponent = 0x4003;
- bcd_var(a).mantissa = 0x3284300000000000;
- </PRE>
- Note, however, that the <A HREF="$$LINK(timath.h/bcd)">bcd</A> type is still a structure.
- </LI>
- </UL>
|