Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
6.3 KiB

  1. //-----------------------------------------------------------------------------
  2. // Package Title ratpak
  3. // File fact.c
  4. // Author Timothy David Corrie Jr. ([email protected])
  5. // Copyright (C) 1995-96 Microsoft
  6. // Date 01-16-95
  7. //
  8. //
  9. // Description
  10. //
  11. // Contains fact(orial) and supporting _gamma functions.
  12. //
  13. //-----------------------------------------------------------------------------
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #if defined( DOS )
  18. #include <dosstub.h>
  19. #else
  20. #include <windows.h>
  21. #endif
  22. #include <ratpak.h>
  23. #define ABSRAT(x) (((x)->pp->sign=1),((x)->pq->sign=1))
  24. #define NEGATE(x) ((x)->pp->sign *= -1)
  25. //-----------------------------------------------------------------------------
  26. //
  27. // FUNCTION: factrat, _gamma, gamma
  28. //
  29. // ARGUMENTS: x PRAT representation of number to take the sine of
  30. //
  31. // RETURN: factorial of x in PRAT form.
  32. //
  33. // EXPLANATION: This uses Taylor series
  34. //
  35. // n
  36. // ___ 2j
  37. // n \ ] A 1 A
  38. // A \ -----[ ---- - ---------------]
  39. // / (2j)! n+2j (n+2j+1)(2j+1)
  40. // /__]
  41. // j=0
  42. //
  43. // / oo
  44. // | n-1 -x __
  45. // This was derived from | x e dx = |
  46. // | | (n) { = (n-1)! for +integers}
  47. // / 0
  48. //
  49. // GregSte showed the above series to be within precision if A was chosen
  50. // big enough.
  51. // A n precision
  52. // Based on the relation ne = A 10 A was chosen as
  53. //
  54. // precision
  55. // A = ln(Base /n)+1
  56. // A += n*ln(A) This is close enough for precision > base and n < 1.5
  57. //
  58. //
  59. //-----------------------------------------------------------------------------
  60. void _gamma( PRAT *pn )
  61. {
  62. PRAT factorial=NULL;
  63. PNUMBER count=NULL;
  64. PRAT tmp=NULL;
  65. PRAT one_pt_five=NULL;
  66. PRAT a=NULL;
  67. PRAT a2=NULL;
  68. PRAT term=NULL;
  69. PRAT sum=NULL;
  70. PRAT err=NULL;
  71. PRAT mpy=NULL;
  72. PRAT ratprec = NULL;
  73. PRAT ratRadix = NULL;
  74. long oldprec;
  75. // Set up constants and initial conditions
  76. oldprec = maxout;
  77. ratprec = longtorat( oldprec );
  78. // Find the best 'A' for convergence to the required precision.
  79. a=longtorat( nRadix );
  80. lograt(&a);
  81. mulrat(&a,ratprec);
  82. // Really is -ln(n)+1, but -ln(n) will be < 1
  83. // if we scale n between 0.5 and 1.5
  84. addrat(&a,rat_two);
  85. DUPRAT(tmp,a);
  86. lograt(&tmp);
  87. mulrat(&tmp,*pn);
  88. addrat(&a,tmp);
  89. addrat(&a,rat_one);
  90. // Calculate the necessary bump in precision and up the precision.
  91. // The following code is equivalent to
  92. // maxout += ln(exp(a)*pow(a,n+1.5))-ln(nRadix));
  93. DUPRAT(tmp,*pn);
  94. one_pt_five=longtorat( 3L );
  95. divrat( &one_pt_five, rat_two );
  96. addrat( &tmp, one_pt_five );
  97. DUPRAT(term,a);
  98. powrat( &term, tmp );
  99. DUPRAT( tmp, a );
  100. exprat( &tmp );
  101. mulrat( &term, tmp );
  102. lograt( &term );
  103. ratRadix = longtorat( nRadix );
  104. DUPRAT(tmp,ratRadix);
  105. lograt( &tmp );
  106. subrat( &term, tmp );
  107. maxout += rattolong( term );
  108. // Set up initial terms for series, refer to series in above comment block.
  109. DUPRAT(factorial,rat_one); // Start factorial out with one
  110. count = longtonum( 0L, BASEX );
  111. DUPRAT(mpy,a);
  112. powrat(&mpy,*pn);
  113. // a2=a^2
  114. DUPRAT(a2,a);
  115. mulrat(&a2,a);
  116. // sum=(1/n)-(a/(n+1))
  117. DUPRAT(sum,rat_one);
  118. divrat(&sum,*pn);
  119. DUPRAT(tmp,*pn);
  120. addrat(&tmp,rat_one);
  121. DUPRAT(term,a);
  122. divrat(&term,tmp);
  123. subrat(&sum,term);
  124. DUPRAT(err,ratRadix);
  125. NEGATE(ratprec);
  126. powrat(&err,ratprec);
  127. divrat(&err,ratRadix);
  128. // Just get something not tiny in term
  129. DUPRAT(term, rat_two );
  130. // Loop until precision is reached, or asked to halt.
  131. while ( !zerrat( term ) && rat_gt( term, err) && !fhalt )
  132. {
  133. addrat(pn,rat_two);
  134. // WARNING: mixing numbers and rationals here.
  135. // for speed and efficiency.
  136. INC(count);
  137. mulnumx(&(factorial->pp),count);
  138. INC(count)
  139. mulnumx(&(factorial->pp),count);
  140. divrat(&factorial,a2);
  141. DUPRAT(tmp,*pn);
  142. addrat( &tmp, rat_one );
  143. destroyrat(term);
  144. createrat(term);
  145. DUPNUM(term->pp,count);
  146. DUPNUM(term->pq,num_one);
  147. addrat( &term, rat_one );
  148. mulrat( &term, tmp );
  149. DUPRAT(tmp,a);
  150. divrat( &tmp, term );
  151. DUPRAT(term,rat_one);
  152. divrat( &term, *pn);
  153. subrat( &term, tmp);
  154. divrat (&term, factorial);
  155. addrat( &sum, term);
  156. ABSRAT(term);
  157. }
  158. // Multiply by factor.
  159. mulrat( &sum, mpy );
  160. // And cleanup
  161. maxout = oldprec;
  162. destroyrat(ratprec);
  163. destroyrat(err);
  164. destroyrat(term);
  165. destroyrat(a);
  166. destroyrat(a2);
  167. destroyrat(tmp);
  168. destroyrat(one_pt_five);
  169. destroynum(count);
  170. destroyrat(factorial);
  171. destroyrat(*pn);
  172. DUPRAT(*pn,sum);
  173. destroyrat(sum);
  174. }
  175. void factrat( PRAT *px )
  176. {
  177. PRAT fact = NULL;
  178. PRAT frac = NULL;
  179. PRAT neg_rat_one = NULL;
  180. DUPRAT(fact,rat_one);
  181. DUPRAT(neg_rat_one,rat_one);
  182. neg_rat_one->pp->sign *= -1;
  183. DUPRAT( frac, *px );
  184. fracrat( &frac );
  185. // Check for negative integers and throw an error.
  186. if ( ( zerrat(frac) || ( LOGRATRADIX(frac) <= -maxout ) ) &&
  187. ( (*px)->pp->sign * (*px)->pq->sign == -1 ) )
  188. {
  189. throw CALC_E_DOMAIN;
  190. }
  191. while ( rat_gt( *px, rat_zero ) && !fhalt &&
  192. ( LOGRATRADIX(*px) > -maxout ) )
  193. {
  194. mulrat( &fact, *px );
  195. subrat( px, rat_one );
  196. }
  197. // Added to make numbers 'close enough' to integers use integer factorial.
  198. if ( LOGRATRADIX(*px) <= -maxout )
  199. {
  200. DUPRAT((*px),rat_zero);
  201. intrat(&fact);
  202. }
  203. while ( rat_lt( *px, neg_rat_one ) && !fhalt )
  204. {
  205. addrat( px, rat_one );
  206. divrat( &fact, *px );
  207. }
  208. if ( rat_neq( *px, rat_zero ) )
  209. {
  210. addrat( px, rat_one );
  211. _gamma( px );
  212. mulrat( px, fact );
  213. }
  214. else
  215. {
  216. DUPRAT(*px,fact);
  217. }
  218. }