Source code of Windows XP (NT5)
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.

377 lines
9.8 KiB

  1. //-----------------------------------------------------------------------------
  2. // Package Title ratpak
  3. // File exp.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 exp, and log functions for rationals
  12. //
  13. //
  14. //-----------------------------------------------------------------------------
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #if defined( DOS )
  18. #include <dosstub.h>
  19. #else
  20. #include <windows.h>
  21. #endif
  22. #include <ratpak.h>
  23. //-----------------------------------------------------------------------------
  24. //
  25. // FUNCTION: exprat
  26. //
  27. // ARGUMENTS: x PRAT representation of number to exponentiate
  28. //
  29. // RETURN: exp of x in PRAT form.
  30. //
  31. // EXPLANATION: This uses Taylor series
  32. //
  33. // n
  34. // ___
  35. // \ ] X
  36. // \ thisterm ; where thisterm = thisterm * ---------
  37. // / j j+1 j j+1
  38. // /__]
  39. // j=0
  40. //
  41. // thisterm = X ; and stop when thisterm < precision used.
  42. // 0 n
  43. //
  44. //-----------------------------------------------------------------------------
  45. void _exprat( PRAT *px )
  46. {
  47. CREATETAYLOR();
  48. addnum(&(pret->pp),num_one, BASEX);
  49. addnum(&(pret->pq),num_one, BASEX);
  50. DUPRAT(thisterm,pret);
  51. n2=longtonum(0L, BASEX);
  52. do {
  53. NEXTTERM(*px, INC(n2) DIVNUM(n2));
  54. } while ( !SMALL_ENOUGH_RAT( thisterm ) && !fhalt );
  55. DESTROYTAYLOR();
  56. }
  57. void exprat( PRAT *px )
  58. {
  59. PRAT pwr=NULL;
  60. PRAT pint=NULL;
  61. long intpwr;
  62. if ( rat_gt( *px, rat_max_exp ) || rat_lt( *px, rat_min_exp ) )
  63. {
  64. // Don't attempt exp of anything large.
  65. throw( CALC_E_DOMAIN );
  66. }
  67. DUPRAT(pwr,rat_exp);
  68. DUPRAT(pint,*px);
  69. intrat(&pint);
  70. intpwr = rattolong(pint);
  71. ratpowlong( &pwr, intpwr );
  72. subrat(px,pint);
  73. // It just so happens to be an integral power of e.
  74. if ( rat_gt( *px, rat_negsmallest ) && rat_lt( *px, rat_smallest ) )
  75. {
  76. DUPRAT(*px,pwr);
  77. }
  78. else
  79. {
  80. _exprat(px);
  81. mulrat(px,pwr);
  82. }
  83. destroyrat( pwr );
  84. destroyrat( pint );
  85. }
  86. //-----------------------------------------------------------------------------
  87. //
  88. // FUNCTION: lograt, _lograt
  89. //
  90. // ARGUMENTS: x PRAT representation of number to logarithim
  91. //
  92. // RETURN: log of x in PRAT form.
  93. //
  94. // EXPLANATION: This uses Taylor series
  95. //
  96. // n
  97. // ___
  98. // \ ] j*(1-X)
  99. // \ thisterm ; where thisterm = thisterm * ---------
  100. // / j j+1 j j+1
  101. // /__]
  102. // j=0
  103. //
  104. // thisterm = X ; and stop when thisterm < precision used.
  105. // 0 n
  106. //
  107. // Number is scaled between one and e_to_one_half prior to taking the
  108. // log. This is to keep execution time from exploding.
  109. //
  110. //
  111. //-----------------------------------------------------------------------------
  112. void _lograt( PRAT *px )
  113. {
  114. CREATETAYLOR();
  115. createrat(thisterm);
  116. // sub one from x
  117. (*px)->pq->sign *= -1;
  118. addnum(&((*px)->pp),(*px)->pq, BASEX);
  119. (*px)->pq->sign *= -1;
  120. DUPRAT(pret,*px);
  121. DUPRAT(thisterm,*px);
  122. n2=longtonum(1L, BASEX);
  123. (*px)->pp->sign *= -1;
  124. do {
  125. NEXTTERM(*px, MULNUM(n2) INC(n2) DIVNUM(n2));
  126. TRIMTOP(*px);
  127. } while ( !SMALL_ENOUGH_RAT( thisterm ) && !fhalt );
  128. DESTROYTAYLOR();
  129. }
  130. void lograt( PRAT *px )
  131. {
  132. BOOL fneglog;
  133. PRAT pwr=NULL; // pwr is the large scaling factor.
  134. PRAT offset=NULL; // offset is the incremental scaling factor.
  135. // Check for someone taking the log of zero or a negative number.
  136. if ( rat_le( *px, rat_zero ) )
  137. {
  138. throw( CALC_E_DOMAIN );
  139. }
  140. // Get number > 1, for scaling
  141. fneglog = rat_lt( *px, rat_one );
  142. if ( fneglog )
  143. {
  144. // WARNING: This is equivalent to doing *px = 1 / *px
  145. PNUMBER pnumtemp=NULL;
  146. pnumtemp = (*px)->pp;
  147. (*px)->pp = (*px)->pq;
  148. (*px)->pq = pnumtemp;
  149. }
  150. // Scale the number within BASEX factor of 1, for the large scale.
  151. // log(x*2^(BASEXPWR*k)) = BASEXPWR*k*log(2)+log(x)
  152. if ( LOGRAT2(*px) > 1 )
  153. {
  154. // Take advantage of px's base BASEX to scale quickly down to
  155. // a reasonable range.
  156. long intpwr;
  157. intpwr=LOGRAT2(*px)-1;
  158. (*px)->pq->exp += intpwr;
  159. pwr=longtorat(intpwr*BASEXPWR);
  160. mulrat(&pwr,ln_two);
  161. // ln(x+e)-ln(x) looks close to e when x is close to one using some
  162. // expansions. This means we can trim past precision digits+1.
  163. TRIMTOP(*px);
  164. }
  165. else
  166. {
  167. DUPRAT(pwr,rat_zero);
  168. }
  169. DUPRAT(offset,rat_zero);
  170. // Scale the number between 1 and e_to_one_half, for the small scale.
  171. while ( rat_gt( *px, e_to_one_half ) && !fhalt )
  172. {
  173. divrat( px, e_to_one_half );
  174. addrat( &offset, rat_one );
  175. }
  176. _lograt(px);
  177. // Add the large and small scaling factors, take into account
  178. // small scaling was done in e_to_one_half chunks.
  179. divrat(&offset,rat_two);
  180. addrat(&pwr,offset);
  181. // And add the resulting scaling factor to the answer.
  182. addrat(px,pwr);
  183. trimit(px);
  184. // If number started out < 1 rescale answer to negative.
  185. if ( fneglog )
  186. {
  187. (*px)->pp->sign *= -1;
  188. }
  189. destroyrat(pwr);
  190. }
  191. void log10rat( PRAT *px )
  192. {
  193. lograt(px);
  194. divrat(px,ln_ten);
  195. }
  196. //---------------------------------------------------------------------------
  197. //
  198. // FUNCTION: powrat
  199. //
  200. // ARGUMENTS: PRAT *px, and PRAT y
  201. //
  202. // RETURN: none, sets *px to *px to the y.
  203. //
  204. // EXPLANATION: This uses x^y=e(y*ln(x)), or a more exact calculation where
  205. // y is an integer.
  206. // Assumes, all checking has been done on validity of numbers.
  207. //
  208. //
  209. //---------------------------------------------------------------------------
  210. void powrat( PRAT *px, PRAT y )
  211. {
  212. PRAT podd=NULL;
  213. PRAT plnx=NULL;
  214. long sign=1;
  215. sign=( (*px)->pp->sign * (*px)->pq->sign );
  216. // Take the absolute value
  217. (*px)->pp->sign = 1;
  218. (*px)->pq->sign = 1;
  219. if ( zerrat( *px ) )
  220. {
  221. // *px is zero.
  222. if ( rat_lt( y, rat_zero ) )
  223. {
  224. throw( CALC_E_DOMAIN );
  225. }
  226. else if ( zerrat( y ) )
  227. {
  228. // *px and y are both zero, special case a 1 return.
  229. DUPRAT(*px,rat_one);
  230. // Ensure sign is positive.
  231. sign = 1;
  232. }
  233. }
  234. else
  235. {
  236. PRAT pxint=NULL;
  237. DUPRAT(pxint,*px);
  238. subrat(&pxint,rat_one);
  239. if ( rat_gt( pxint, rat_negsmallest ) &&
  240. rat_lt( pxint, rat_smallest ) && ( sign == 1 ) )
  241. {
  242. // *px is one, special case a 1 return.
  243. DUPRAT(*px,rat_one);
  244. // Ensure sign is positive.
  245. sign = 1;
  246. }
  247. else
  248. {
  249. // Only do the exp if the number isn't zero or one
  250. DUPRAT(podd,y);
  251. fracrat(&podd);
  252. if ( rat_gt( podd, rat_negsmallest ) && rat_lt( podd, rat_smallest ) )
  253. {
  254. // If power is an integer let ratpowlong deal with it.
  255. PRAT iy = NULL;
  256. long inty;
  257. DUPRAT(iy,y);
  258. subrat(&iy,podd);
  259. inty = rattolong(iy);
  260. DUPRAT(plnx,*px);
  261. lograt(&plnx);
  262. mulrat(&plnx,iy);
  263. if ( rat_gt( plnx, rat_max_exp ) || rat_lt( plnx, rat_min_exp ) )
  264. {
  265. // Don't attempt exp of anything large or small.A
  266. destroyrat(plnx);
  267. destroyrat(iy);
  268. throw( CALC_E_DOMAIN );
  269. }
  270. destroyrat(plnx);
  271. ratpowlong(px,inty);
  272. if ( ( inty & 1 ) == 0 )
  273. {
  274. sign=1;
  275. }
  276. destroyrat(iy);
  277. }
  278. else
  279. {
  280. // power is a fraction
  281. if ( sign == -1 )
  282. {
  283. // And assign the sign after computations, if appropriate.
  284. if ( rat_gt( y, rat_neg_one ) && rat_lt( y, rat_zero ) )
  285. {
  286. // Check to see if reciprocal is odd.
  287. DUPRAT(podd,rat_one);
  288. divrat(&podd,y);
  289. // Only interested in the absval for determining oddness.
  290. podd->pp->sign = 1;
  291. podd->pq->sign = 1;
  292. divrat(&podd,rat_two);
  293. fracrat(&podd);
  294. addrat(&podd,podd);
  295. subrat(&podd,rat_one);
  296. if ( rat_lt( podd, rat_zero ) )
  297. {
  298. // Negative nonodd root of negative number.
  299. destroyrat(podd);
  300. throw( CALC_E_DOMAIN );
  301. }
  302. }
  303. else
  304. {
  305. // Negative nonodd power of negative number.
  306. destroyrat(podd);
  307. throw( CALC_E_DOMAIN );
  308. }
  309. }
  310. else
  311. {
  312. // If the exponent is not odd disregard the sign.
  313. sign = 1;
  314. }
  315. lograt( px );
  316. mulrat( px, y );
  317. exprat( px );
  318. }
  319. destroyrat(podd);
  320. }
  321. destroyrat(pxint);
  322. }
  323. (*px)->pp->sign *= sign;
  324. }