home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 188_01 / trans.doc < prev    next >
Text File  |  1987-09-30  |  14KB  |  275 lines

  1. .mt 0
  2. .mb 11
  3. .po 13
  4. /*
  5. HEADER:        ;
  6. TITLE:        C elementary transcendentals;
  7. VERSION:    1.0;
  8.  
  9. DESCRIPTION:       Source    code    for   all   standard    C                            
  10.                transcendentals
  11.  
  12.         Employs  ldexp()  and  frexp()  functions;  if                
  13.                suitable  versions  of these are  not  provided                
  14.                by  a given compiler,  the versions provided in                
  15.                source  code  will require  adaptation  to  the                
  16.                double float formats of the compiler.
  17.  
  18. KEYWORDS:    Transcendentals, library;
  19. SYSTEM:        CP/M-80, V3.1;
  20. FILENAME:    TRANS.C;
  21. WARNINGS:      frexp()   and  ldexp()  are   implementation                
  22.                dependent.   The  compiler  employed  does  not 
  23.                support    minus   (-)   unary   operators   in                
  24.                initializer  lists,  which are required by  the                
  25.                code.
  26. AUTHORS:    Tim Prince;
  27. COMPILERS:    MIX C, v2.0.1;
  28. */
  29.               Transcendental Function Algorithms
  30.  
  31.      All  programming languages which are descended from  FOR-
  32. TRAN  or  Algol include pre-defined transcendental  functions.     
  33. Standard  textbooks on programming assume that the usual  math 
  34. functions  are already available and not worth the  paper  re-
  35. quired  to describe how they might be coded.   This is  unfor-
  36. tunate,  as few computer systems provide reliable transcenden-
  37. tals,  and  a basic understanding of their contents is helpful 
  38. in their use.
  39.  
  40.      The  following  examples use polynomial  representations, 
  41. because  they lead to compact code and give  average  accuracy 
  42. within one bit of the best available.  Faster algorithms exist 
  43. but require more code or data storage,  if written in the same 
  44. language.   Commercial  versions of the functions are  usually 
  45. written  in  assembler,  but the ideas are best  expressed  in 
  46. higher  level languages.   Obscure tricks which  an  anonymous 
  47. coder thought would improve speed are useless when the program 
  48. fails  and the source code is not available.   These functions 
  49. have been tested in nearly the same form on several  computers 
  50. in both FORTRAN and C.
  51.  
  52.      The  author's hope is that these examples may set a mini-
  53. mum standard for accuracy and speed of C library  transcenden-
  54. tals.   Failing  this,  the  individual user should  have  the 
  55. opportunity  to check whether any deficiencies of his code may 
  56. be due to the library provided with the C compiler.  C's  soon 
  57. to  be standardized support of bit fields and low level opera-
  58. tions on doubles helps in the expression of these  algorithms.  
  59. Since  C,  even in the future ANSI standard,  will not support 
  60. pure single precision on computers which were not designed for 
  61. mixed precision arithmetic, and the standard library functions 
  62. are double, we show only the double precision, with the under-
  63. standing that changes in the polynomials would adapt to  other 
  64. precisions.   The file TRANSLIB.FOR shows FORTRAN versions  in 
  65. single precision, which should serve as a demonstration of the 
  66. changes required to vary precision and language.
  67.  
  68.      The  polynomial  coefficients were determined by  running 
  69. one  of  Steve Ruzinsky's programs (1).   In  each  case,  the 
  70. polynomial  is derived by truncating a standard Taylor  series 
  71. or  rational  polynomial representation of  the  function  and 
  72. using Steve's program to obtain more accuracy with fewer terms 
  73. in the required range.   In some cases, 25 digit arithmetic is 
  74. required  to fit a polynomial accurate to at least 16  digits.  
  75. Tables of coefficients have been generated for polynomials  of 
  76. any accuracy required up to 20 or more significant digits.
  77.  
  78.      Trigonometric  functions can be calculated with  adequate 
  79. efficiency  using portable code,  even in archaic dialects  of 
  80. FORTRAN,  Pascal,  and C.   When using polynomials, it appears 
  81. best  to use the sin() function as the basic series and calcu-
  82. late the others from it.   A polynomial for tan() requires  as 
  83. many terms as sin() and cos() together.  Since cos() and tan() 
  84. may be calculated from sin(),  only one shorter table of coef-
  85. ficients  is  needed.   In effect,  tan() is calculated  by  a 
  86. rational polynomial approximation.   Expressing these trigono-
  87. metric relationships by #define teaches the preprocessor alge-
  88. bra  which  an  optimizing compiler could  use  to  advantage.  
  89. Check  that your compiler does not execute functions  multiple 
  90. times  as a result of macro expansion.   Tan() could be calcu-
  91. lated much faster with a big table as is built in to the 8087, 
  92. but  most programs we have seen spend more time on  sin()  and 
  93. cos().
  94.  
  95.      The  first  step in calculating sin() is  to  reduce  the 
  96. range to |x| < pi/2 by subtracting the nearest multiple of pi.  
  97. The  ODD() function shown assumes that (int) will extract  the 
  98. low  order  bits  in case the argument  exceeds  maxint.   The 
  99. multiplication  and subtraction should be done in long  double 
  100. if it is available, but in any case the range reduction should 
  101. not reduce accuracy when the original argument was already  in 
  102. the  desired  range.   The  method most often used  saves  one 
  103. divide (which may be changed to a multiply), at the cost of an 
  104. unnecessary  roundoff.   Worse,  the result may  underflow  to 
  105. zero.   Underflows  in the code shown occur only where a  zero 
  106. does not affect the result.  With the precautions taken, extra 
  107. precision   is  not  needed  anywhere  other  than  the  range 
  108. reduction.
  109.  
  110.      Most  computer  systems include a  polynomial  evaluation 
  111. function,  sometimes in microcode.  To save space we prefer to 
  112. use such a function even though it may be slower than  writing 
  113. out  the  polynomial in Horner form.   Such functions  operate 
  114. like poly() shown here,  but (presumably) faster.   This modu-
  115. larity  permits  special  hardware features to  be  used  more 
  116. effectively,  although the time required to call another func-
  117. tion may be excessive.  Loop unrolling (shown here) or odd and 
  118. even  summing (see exp2()) are often  effective.   The  series 
  119. used  for elementary functions have terms increasing in magni-
  120. tude fast enough so that there is no need for extra  precision 
  121. intermediate computation.
  122.  
  123.      The  arctan function uses several substitutions to reduce 
  124. to a range of 0 < x < 1.   Although the Taylor series does not 
  125. converge over this range,  the minimax polynomial does, but so 
  126. many terms are needed that one further step of range reduction 
  127. is preferred.   Code length may be traded for speed by using a 
  128. table of tangents with a shorter series.   A rational  polyno-
  129. mial(3)  is used by many run-time libraries,  at some cost  of 
  130. accuracy.   A  series with one less term would still give over 
  131. 15  digits  accuracy,  which is the maximum possible  on  some 
  132. systems.
  133.  
  134.      Although  log base 2 is not usually included in the  list 
  135. of  library functions,  it is almost always used as the  basic 
  136. logarithm  for binary floating point,  because it is the  most 
  137. efficient  base for exponentiation with a float  power.   Many 
  138. implementations fail to obtain the logarithm of numbers  close 
  139. to 1.   The following routine is the most widely tested of the 
  140. examples  given here,  and has been found accurate on all  ma-
  141. chines which subtract 1 accurately (some don't!).   In theory, 
  142. precision  is  lost when the exponent is added in at the  end, 
  143. but  this  is not serious in the most common cases of  numbers 
  144. near 1.  Making the function long double would correct this.
  145.  
  146.      Log2  can  be written in portable code  if  the  standard 
  147. functions  frexp() and ldexp() for extracting and changing the 
  148. exponent field of a floating point number are  available.   On 
  149. many  systems,  adequate speed will not be obtained unless the 
  150. code  is  supplied in line.   This should  be  possible  using 
  151. unions of structures,  but direct use of any applicable float-
  152. ing point hardware instructions is preferable.   The algorithm 
  153. requires separate calculation of the log of a number near 1 by 
  154. a  series,  which is added to the scale (nearest integer power 
  155. of 2) of the argument.
  156.  
  157.      Using  bit  fields  of structures as  an  alternative  to 
  158. frexp() and ldexp() can be tricky,  but will allow a short int 
  159. comparison to be substituted for the float comparison. The DEC 
  160. system  is unusual in that floating point numbers  are  stored 
  161. with  byte pairs reversed while integers are stored with  full 
  162. reverse byte order.   This may not ruin the bit field code, if 
  163. no  field crosses a 16-bit boundary.   The C function  frexp() 
  164. conflicts  with  the  suggested IEEE standard  which  gives  a 
  165. result just greater than 1 rather than just less than 1.
  166.  
  167.      A  common error in commercial implementations of log() is 
  168. to bypass the conversion of a comparison into an increment  of 
  169. the  scale  by subtracting and adding sqrt(.5) instead  of  1.  
  170. This  has  never been seen to work well,  as sqrt(.5)  is  not 
  171. represented exactly, and all significance of an argument which 
  172. is  near  1  may be lost.   It isn't even as fast  unless  the 
  173. machine  is one which is better suited to  extended  precision 
  174. floating  point  than integer and logical  operations.   Since 
  175. most systems have immediate constant representations of 1. and 
  176. 2., the difference in code length is small.
  177.  
  178.      In  a  full IEEE standard(3)  system,  log()  would  need 
  179. special  code to take care of log(0) and infinities and assure 
  180. that accuracy is not lost on subnormals.   The code shown will 
  181. give  a system-dependent result for log(0) which is such  that 
  182. exp(log(0)) still returns 0.
  183.  
  184.      The  exponential  is the most difficult of  the  standard 
  185. functions to calculate with full accuracy.   It could be writ-
  186. ten  in  portable  code if there were a way to  ascertain  the 
  187. exponent range at compile time;  IEEE P754 dictates a slightly 
  188. different  range from older systems and requires special  case 
  189. handling of out of range arguments.   If ldexp() takes care of 
  190. over- and underflow, these checks may be omitted.  Many varia-
  191. tions may be found,  but they have in common a range reduction 
  192. based on splitting the argument into an integer and a fractio-
  193. nal part, raising 2 to the power of each part, and (in effect) 
  194. multiplying to get the result.
  195.  
  196.      Unlike the other functions,  which have no even terms  in 
  197. their Taylor series,  exponentiation has a symmetry which  can 
  198. be  exploited  only in a rational approximation.   Since  
  199. 2^(-x)=1/2^x,  the rational polynomial takes the form 
  200. P(x)/P(-x),  where the numerator and denominator are identical 
  201. except for the sign of the odd power terms.   Only half of the 
  202. terms  need to be evaluated.
  203.  
  204.      The  coefficients may be calculated by pencil  and  paper 
  205. algebra,  converting  a continued fraction(4) into a  rational 
  206. approximation(5).  Since the equations for the coefficients to 
  207. fit the approximation to a set of points take the same form as 
  208. for  a simple polynomial,  the minimax fitting program may  be 
  209. used to reduce the number of terms required.  The precision of 
  210. the  final result cannot be as great as the precision  of  the 
  211. numerator  and denominator polynomials,  since changes of  the 
  212. last  bit  in  numerator and denominator change  the  quotient 
  213. irregularly but by an average of two bits.   Use of tables  to 
  214. reduce  the  number  of  terms required would  speed  up  this 
  215. function.
  216.  
  217.      Sinh()  should  have its own polynomial for |x|  <  1  to 
  218. maintain accuracy and save the time which would be required to 
  219. calculate  even power terms in exp().   Tanh() should  include 
  220. code  to  give +-1 directly as a result for  large  arguments.  
  221. The  solution  using a special exp-1 function is workable  but 
  222. slower  and incompatible with the rational  approximation  for 
  223. exp().
  224.  
  225. .cp 5
  226.      Sqrt()  is  best coded as an arithmetic operation on  the 
  227. same level as divide,  so that it can execute faster than  and 
  228. as accurately as divide.   Many systems fail to do this and so 
  229. a typical procedure is shown.  A minimax polynomial is used to 
  230. get  an  approximation accurate to 2 or 3 digits,  and  Newton 
  231. iterations  are performed until maximum accuracy  is  reached.  
  232. It is faster to perform the maximum number of iterations which 
  233. may  be  required rather than to go until the  last  iteration 
  234. makes no significant change.  If the arithmetic operations are 
  235. properly  rounded,  the result will be within one bit of  full 
  236. machine accuracy.
  237.  
  238.      The  code required to implement the algorithms appears to 
  239. be  consistent  with published standards for the  C  language.  
  240. Some compiler designers consider that the Reference  Manual(6) 
  241. definition  is satisfied by accepting but ignoring minus signs 
  242. in  initializers.   The code was tested by patching  the  con-
  243. stants  in  the  compiler output code.   This problem  may  be 
  244. circumvented by expanding the polynomials in line,  which is a 
  245. favorable  trade of length for speed on some  machines.   This 
  246. sort  of  problem  does not occur even in  TRANS   DOCee!Xt code.
  247.  
  248.      Tests show that FORTRAN and C versions of these functions 
  249. may  be improved in speed or code length by assembler  coding.  
  250. Except possibly for exp(),  the accuracy of these functions is 
  251. as  good  as the best and frequently better  than  the  store-
  252. bought  versions.   
  253. .pa
  254. References
  255.  
  256. 1.Ruzinsky,  Steven  A.   "A Simple Minimax  Algorithm,"  Dr. 
  257. Dobb's Journal #93 pp. 84-91, July 1984
  258.  
  259. 2.Moshier,  Stephen L.   "Computer Approximations,"  Byte pp. 
  260. 161-178, Apr. 1986
  261.  
  262. 3.Cody,  W.  J., Karpinski, R."A Proposed Radix- and 
  263. Word-length-independent  Standard for Floating-point  Arithme-
  264. tic," IEEE Micro pp. 86-100, August 1984
  265.  
  266. 4.Abramowitz,  M.,  Stegun,  I.   "Handbook  of  Mathematical 
  267. Functions," Dover 1968
  268.  
  269. 5.Press,  W.H. et al.  "Numerical Recipes," Cambridge Univer-
  270. sity Press 1986
  271.  
  272. 6.Ritchie, Dennis M.  "The C Programming Language - Reference 
  273. Manual,"  in UNIX Programmer's Manual,  v.2, Holt Rinehart amd 
  274. Winston, 1983
  275.