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.

299 lines
6.8 KiB

  1. //-----------------------------------------------------------------------------
  2. // Package Title ratpak
  3. // File rat.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 mul, div, add, and other support functions for rationals.
  12. //
  13. //
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <malloc.h>
  19. #include <stdlib.h>
  20. #if defined( DOS )
  21. #include <dosstub.h>
  22. #else
  23. #include <windows.h>
  24. #endif
  25. #include <ratpak.h>
  26. //-----------------------------------------------------------------------------
  27. //
  28. // FUNCTION: gcdrat
  29. //
  30. // ARGUMENTS: pointer to a rational.
  31. //
  32. //
  33. // RETURN: None, changes first pointer.
  34. //
  35. // DESCRIPTION: Divides p and q in rational by the G.C.D.
  36. // of both. It was hoped this would speed up some
  37. // calculations, and until the above trimming was done it
  38. // did, but after trimming gcdratting, only slows things
  39. // down.
  40. //
  41. //-----------------------------------------------------------------------------
  42. void gcdrat( PRAT *pa )
  43. {
  44. PNUMBER pgcd=NULL;
  45. PRAT a=NULL;
  46. a=*pa;
  47. pgcd = gcd( a->pp, a->pq );
  48. if ( !zernum( pgcd ) )
  49. {
  50. divnumx( &(a->pp), pgcd );
  51. divnumx( &(a->pq), pgcd );
  52. }
  53. destroynum( pgcd );
  54. *pa=a;
  55. }
  56. //-----------------------------------------------------------------------------
  57. //
  58. // FUNCTION: fracrat
  59. //
  60. // ARGUMENTS: pointer to a rational a second rational.
  61. //
  62. // RETURN: None, changes pointer.
  63. //
  64. // DESCRIPTION: Does the rational equivalent of frac(*pa);
  65. //
  66. //-----------------------------------------------------------------------------
  67. void fracrat( PRAT *pa )
  68. {
  69. long trim;
  70. remnum( &((*pa)->pp), (*pa)->pq, BASEX );
  71. //Get *pa back in the integer over integer form.
  72. RENORMALIZE(*pa);
  73. }
  74. //-----------------------------------------------------------------------------
  75. //
  76. // FUNCTION: mulrat
  77. //
  78. // ARGUMENTS: pointer to a rational a second rational.
  79. //
  80. // RETURN: None, changes first pointer.
  81. //
  82. // DESCRIPTION: Does the rational equivalent of *pa *= b.
  83. // Assumes nRadix is the nRadix of both numbers.
  84. //
  85. //-----------------------------------------------------------------------------
  86. void mulrat( PRAT *pa, PRAT b )
  87. {
  88. // Only do the multiply if it isn't zero.
  89. if ( !zernum( (*pa)->pp ) )
  90. {
  91. mulnumx( &((*pa)->pp), b->pp );
  92. mulnumx( &((*pa)->pq), b->pq );
  93. trimit(pa);
  94. }
  95. else
  96. {
  97. // If it is zero, blast a one in the denominator.
  98. DUPNUM( ((*pa)->pq), num_one );
  99. }
  100. #ifdef MULGCD
  101. gcdrat( pa );
  102. #endif
  103. }
  104. //-----------------------------------------------------------------------------
  105. //
  106. // FUNCTION: divrat
  107. //
  108. // ARGUMENTS: pointer to a rational a second rational.
  109. //
  110. // RETURN: None, changes first pointer.
  111. //
  112. // DESCRIPTION: Does the rational equivalent of *pa /= b.
  113. // Assumes nRadix is the nRadix of both numbers.
  114. //
  115. //-----------------------------------------------------------------------------
  116. void divrat( PRAT *pa, PRAT b )
  117. {
  118. if ( !zernum( (*pa)->pp ) )
  119. {
  120. // Only do the divide if the top isn't zero.
  121. mulnumx( &((*pa)->pp), b->pq );
  122. mulnumx( &((*pa)->pq), b->pp );
  123. if ( zernum( (*pa)->pq ) )
  124. {
  125. // raise an exception if the bottom is 0.
  126. throw( CALC_E_DIVIDEBYZERO );
  127. }
  128. trimit(pa);
  129. }
  130. else
  131. {
  132. // Top is zero.
  133. if ( zerrat( b ) )
  134. {
  135. // If bottom is zero
  136. // 0 / 0 is indefinite, raise an exception.
  137. throw( CALC_E_INDEFINITE );
  138. }
  139. else
  140. {
  141. // 0/x make a unique 0.
  142. DUPNUM( ((*pa)->pq), num_one );
  143. }
  144. }
  145. #ifdef DIVGCD
  146. gcdrat( pa );
  147. #endif
  148. }
  149. //-----------------------------------------------------------------------------
  150. //
  151. // FUNCTION: subrat
  152. //
  153. // ARGUMENTS: pointer to a rational a second rational.
  154. //
  155. // RETURN: None, changes first pointer.
  156. //
  157. // DESCRIPTION: Does the rational equivalent of *pa += b.
  158. // Assumes base is internal througought.
  159. //
  160. //-----------------------------------------------------------------------------
  161. void subrat( PRAT *pa, PRAT b )
  162. {
  163. b->pp->sign *= -1;
  164. addrat( pa, b );
  165. b->pp->sign *= -1;
  166. }
  167. //-----------------------------------------------------------------------------
  168. //
  169. // FUNCTION: addrat
  170. //
  171. // ARGUMENTS: pointer to a rational a second rational.
  172. //
  173. // RETURN: None, changes first pointer.
  174. //
  175. // DESCRIPTION: Does the rational equivalent of *pa += b.
  176. // Assumes base is internal througought.
  177. //
  178. //-----------------------------------------------------------------------------
  179. void addrat( PRAT *pa, PRAT b )
  180. {
  181. PNUMBER bot=NULL;
  182. if ( equnum( (*pa)->pq, b->pq ) )
  183. {
  184. // Very special case, q's match.,
  185. // make sure signs are involved in the calculation
  186. // we have to do this since the optimization here is only
  187. // working with the top half of the rationals.
  188. (*pa)->pp->sign *= (*pa)->pq->sign;
  189. (*pa)->pq->sign = 1;
  190. b->pp->sign *= b->pq->sign;
  191. b->pq->sign = 1;
  192. addnum( &((*pa)->pp), b->pp, BASEX );
  193. }
  194. else
  195. {
  196. // Usual case q's aren't the same.
  197. DUPNUM( bot, (*pa)->pq );
  198. mulnumx( &bot, b->pq );
  199. mulnumx( &((*pa)->pp), b->pq );
  200. mulnumx( &((*pa)->pq), b->pp );
  201. addnum( &((*pa)->pp), (*pa)->pq, BASEX );
  202. destroynum( (*pa)->pq );
  203. (*pa)->pq = bot;
  204. trimit(pa);
  205. // Get rid of negative zeroes here.
  206. (*pa)->pp->sign *= (*pa)->pq->sign;
  207. (*pa)->pq->sign = 1;
  208. }
  209. #ifdef ADDGCD
  210. gcdrat( pa );
  211. #endif
  212. }
  213. //-----------------------------------------------------------------------------
  214. //
  215. // FUNCTION: rootrat
  216. //
  217. // PARAMETERS: y prat representation of number to take the root of
  218. // n prat representation of the root to take.
  219. //
  220. // RETURN: bth root of a in rat form.
  221. //
  222. // EXPLANATION: This is now a stub function to powrat().
  223. //
  224. //-----------------------------------------------------------------------------
  225. void rootrat( PRAT *py, PRAT n )
  226. {
  227. PRAT oneovern=NULL;
  228. DUPRAT(oneovern,rat_one);
  229. divrat(&oneovern,n);
  230. powrat( py, oneovern );
  231. destroyrat(oneovern);
  232. }
  233. //-----------------------------------------------------------------------------
  234. //
  235. // FUNCTION: zerrat
  236. //
  237. // ARGUMENTS: Rational number.
  238. //
  239. // RETURN: Boolean
  240. //
  241. // DESCRIPTION: Returns true if input is zero.
  242. // False otherwise.
  243. //
  244. //-----------------------------------------------------------------------------
  245. BOOL zerrat( PRAT a )
  246. {
  247. return( zernum(a->pp) );
  248. }