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.

410 lines
12 KiB

  1. //-----------------------------------------------------------------------------
  2. // Package Title ratpak
  3. // File basex.c
  4. // Author Timothy David Corrie Jr. ([email protected])
  5. // Copyright (C) 1995-97 Microsoft
  6. // Date 03-14-97
  7. //
  8. //
  9. // Description
  10. //
  11. // Contains number routines for internal base computations, these assume
  12. // internal base is a power of 2.
  13. //
  14. //-----------------------------------------------------------------------------
  15. #if defined( DOS )
  16. #include <dosstub.h>
  17. #else
  18. #include <windows.h>
  19. #endif
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <malloc.h>
  23. #include <stdlib.h>
  24. #include <ratpak.h>
  25. // WARNING: This assumes return of a 64 bit entity is in edx:eax
  26. // This assumption SHOULD always be true on X86
  27. #pragma warning( disable : 4035 )
  28. DWORDLONG __inline Mul32x32( IN DWORD a, IN DWORD b )
  29. {
  30. #ifdef _X86_
  31. __asm {
  32. mov eax, b
  33. mul a
  34. }
  35. #else
  36. return (DWORDLONG)a * b;
  37. #endif
  38. }
  39. #pragma warning( default : 4035 )
  40. // Yeah well when the F__KING COMPILER gets a clue I'll change this back to
  41. // an inline (as opposed to the compiler looking at fastcall putting the args
  42. // in registers, oh and then a) not making this inline, and b) pushing the
  43. // values anyway!
  44. #ifdef _X86_
  45. #define Shr32xbase(x) \
  46. __asm { mov eax,DWORD PTR [x] } \
  47. __asm { mov edx,DWORD PTR [x+4] } \
  48. __asm { shrd eax,edx,BASEXPWR } \
  49. __asm { shr edx,BASEXPWR } \
  50. __asm { mov DWORD PTR [x],eax } \
  51. __asm { mov DWORD PTR [x+4],edx }
  52. #else
  53. #define Shr32xbase(x) (x >>= BASEXPWR);
  54. #endif
  55. void _mulnumx( PNUMBER *pa, PNUMBER b );
  56. //----------------------------------------------------------------------------
  57. //
  58. // FUNCTION: mulnumx
  59. //
  60. // ARGUMENTS: pointer to a number and a second number, the
  61. // base is always BASEX.
  62. //
  63. // RETURN: None, changes first pointer.
  64. //
  65. // DESCRIPTION: Does the number equivalent of *pa *= b.
  66. // This is a stub which prevents multiplication by 1, this is a big speed
  67. // improvement.
  68. //
  69. //----------------------------------------------------------------------------
  70. void __inline mulnumx( PNUMBER *pa, PNUMBER b )
  71. {
  72. if ( b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0 )
  73. {
  74. // If b is not one we multiply
  75. if ( (*pa)->cdigit > 1 || (*pa)->mant[0] != 1 || (*pa)->exp != 0 )
  76. {
  77. // pa and b are both nonone.
  78. _mulnumx( pa, b );
  79. }
  80. else
  81. {
  82. // if pa is one and b isn't just copy b. and adjust the sign.
  83. long sign = (*pa)->sign;
  84. DUPNUM(*pa,b);
  85. (*pa)->sign *= sign;
  86. }
  87. }
  88. else
  89. {
  90. // B is +/- 1, But we do have to set the sign.
  91. (*pa)->sign *= b->sign;
  92. }
  93. }
  94. //----------------------------------------------------------------------------
  95. //
  96. // FUNCTION: _mulnumx
  97. //
  98. // ARGUMENTS: pointer to a number and a second number, the
  99. // base is always BASEX.
  100. //
  101. // RETURN: None, changes first pointer.
  102. //
  103. // DESCRIPTION: Does the number equivalent of *pa *= b.
  104. // Assumes the base is BASEX of both numbers. This algorithm is the
  105. // same one you learned in gradeschool, except the base isn't 10 it's
  106. // BASEX.
  107. //
  108. //----------------------------------------------------------------------------
  109. void _mulnumx( PNUMBER *pa, PNUMBER b )
  110. {
  111. PNUMBER c=NULL; // c will contain the result.
  112. PNUMBER a=NULL; // a is the dereferenced number pointer from *pa
  113. MANTTYPE *ptra; // ptra is a pointer to the mantissa of a.
  114. MANTTYPE *ptrb; // ptrb is a pointer to the mantissa of b.
  115. MANTTYPE *ptrc; // ptrc is a pointer to the mantissa of c.
  116. MANTTYPE *ptrcoffset; // ptrcoffset, is the anchor location of the next
  117. // single digit multiply partial result.
  118. long iadigit=0; // Index of digit being used in the first number.
  119. long ibdigit=0; // Index of digit being used in the second number.
  120. MANTTYPE da=0; // da is the digit from the fist number.
  121. TWO_MANTTYPE cy=0; // cy is the carry resulting from the addition of
  122. // a multiplied row into the result.
  123. TWO_MANTTYPE mcy=0; // mcy is the resultant from a single
  124. // multiply, AND the carry of that multiply.
  125. long icdigit=0; // Index of digit being calculated in final result.
  126. a=*pa;
  127. ibdigit = a->cdigit + b->cdigit - 1;
  128. createnum( c, ibdigit + 1 );
  129. c->cdigit = ibdigit;
  130. c->sign = a->sign * b->sign;
  131. c->exp = a->exp + b->exp;
  132. ptra = MANT(a);
  133. ptrcoffset = MANT(c);
  134. for ( iadigit = a->cdigit; iadigit > 0; iadigit-- )
  135. {
  136. da = *ptra++;
  137. ptrb = MANT(b);
  138. // Shift ptrc, and ptrcoffset, one for each digit
  139. ptrc = ptrcoffset++;
  140. for ( ibdigit = b->cdigit; ibdigit > 0; ibdigit-- )
  141. {
  142. cy = 0;
  143. mcy = Mul32x32( da, *ptrb );
  144. if ( mcy )
  145. {
  146. icdigit = 0;
  147. if ( ibdigit == 1 && iadigit == 1 )
  148. {
  149. c->cdigit++;
  150. }
  151. }
  152. // If result is nonzero, or while result of carry is nonzero...
  153. while ( mcy || cy )
  154. {
  155. // update carry from addition(s) and multiply.
  156. cy += (TWO_MANTTYPE)ptrc[icdigit]+((DWORD)mcy&((DWORD)~BASEX));
  157. // update result digit from
  158. ptrc[icdigit++]=(MANTTYPE)((DWORD)cy&((DWORD)~BASEX));
  159. // update carries from
  160. Shr32xbase( mcy );
  161. Shr32xbase( cy );
  162. }
  163. *ptrb++;
  164. *ptrc++;
  165. }
  166. }
  167. // prevent different kinds of zeros, by stripping leading duplicate zeroes.
  168. // digits are in order of increasing significance.
  169. while ( c->cdigit > 1 && MANT(c)[c->cdigit-1] == 0 )
  170. {
  171. c->cdigit--;
  172. }
  173. destroynum( *pa );
  174. *pa=c;
  175. }
  176. //-----------------------------------------------------------------------------
  177. //
  178. // FUNCTION: numpowlongx
  179. //
  180. // ARGUMENTS: root as number power as long
  181. // number.
  182. //
  183. // RETURN: None root is changed.
  184. //
  185. // DESCRIPTION: changes numeric representation of root to
  186. // root ** power. Assumes base BASEX
  187. // decomposes the exponent into it's sums of powers of 2, so on average
  188. // it will take n+n/2 multiplies where n is the highest on bit.
  189. //
  190. //-----------------------------------------------------------------------------
  191. void numpowlongx( IN OUT PNUMBER *proot, IN long power )
  192. {
  193. PNUMBER lret=NULL;
  194. lret = longtonum( 1, BASEX );
  195. // Once the power remaining is zero we are done.
  196. while ( power > 0 )
  197. {
  198. // If this bit in the power decomposition is on, multiply the result
  199. // by the root number.
  200. if ( power & 1 )
  201. {
  202. mulnumx( &lret, *proot );
  203. }
  204. // multiply the root number by itself to scale for the next bit (i.e.
  205. // square it.
  206. mulnumx( proot, *proot );
  207. // move the next bit of the power into place.
  208. power >>= 1;
  209. }
  210. destroynum( *proot );
  211. *proot=lret;
  212. }
  213. void _divnumx( PNUMBER *pa, PNUMBER b );
  214. //----------------------------------------------------------------------------
  215. //
  216. // FUNCTION: divnumx
  217. //
  218. // ARGUMENTS: pointer to a number a second number.
  219. //
  220. // RETURN: None, changes first pointer.
  221. //
  222. // DESCRIPTION: Does the number equivalent of *pa /= b.
  223. // Assumes nRadix is the internal nRadix representation.
  224. // This is a stub which prevents division by 1, this is a big speed
  225. // improvement.
  226. //
  227. //----------------------------------------------------------------------------
  228. void __inline divnumx( PNUMBER *pa, PNUMBER b )
  229. {
  230. if ( b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0 )
  231. {
  232. // b is not one.
  233. if ( (*pa)->cdigit > 1 || (*pa)->mant[0] != 1 || (*pa)->exp != 0 )
  234. {
  235. // pa and b are both not one.
  236. _divnumx( pa, b );
  237. }
  238. else
  239. {
  240. // if pa is one and b is not one, just copy b, and adjust the sign.
  241. long sign = (*pa)->sign;
  242. DUPNUM(*pa,b);
  243. (*pa)->sign *= sign;
  244. }
  245. }
  246. else
  247. {
  248. // b is one so don't divide, but set the sign.
  249. (*pa)->sign *= b->sign;
  250. }
  251. }
  252. //----------------------------------------------------------------------------
  253. //
  254. // FUNCTION: _divnumx
  255. //
  256. // ARGUMENTS: pointer to a number a second number.
  257. //
  258. // RETURN: None, changes first pointer.
  259. //
  260. // DESCRIPTION: Does the number equivalent of *pa /= b.
  261. // Assumes nRadix is the internal nRadix representation.
  262. //
  263. //----------------------------------------------------------------------------
  264. void _divnumx( PNUMBER *pa, PNUMBER b )
  265. {
  266. PNUMBER a=NULL; // a is the dereferenced number pointer from *pa
  267. PNUMBER c=NULL; // c will contain the result.
  268. PNUMBER lasttmp = NULL; // lasttmp allows a backup when the algorithm
  269. // guesses one bit too far.
  270. PNUMBER tmp = NULL; // current guess being worked on for divide.
  271. PNUMBER rem = NULL; // remainder after applying guess.
  272. long cdigits; // count of digits for answer.
  273. MANTTYPE *ptrc; // ptrc is a pointer to the mantissa of c.
  274. long thismax = maxout+ratio; // set a maximum number of internal digits
  275. // to shoot for in the divide.
  276. a=*pa;
  277. if ( thismax < a->cdigit )
  278. {
  279. // a has more digits than precision specified, bump up digits to shoot
  280. // for.
  281. thismax = a->cdigit;
  282. }
  283. if ( thismax < b->cdigit )
  284. {
  285. // b has more digits than precision specified, bump up digits to shoot
  286. // for.
  287. thismax = b->cdigit;
  288. }
  289. // Create c (the divide answer) and set up exponent and sign.
  290. createnum( c, thismax + 1 );
  291. c->exp = (a->cdigit+a->exp) - (b->cdigit+b->exp) + 1;
  292. c->sign = a->sign * b->sign;
  293. ptrc = MANT(c) + thismax;
  294. cdigits = 0;
  295. DUPNUM( rem, a );
  296. rem->sign = b->sign;
  297. rem->exp = b->cdigit + b->exp - rem->cdigit;
  298. while ( cdigits++ < thismax && !zernum(rem) )
  299. {
  300. long digit = 0;
  301. *ptrc = 0;
  302. while ( !lessnum( rem, b ) )
  303. {
  304. digit = 1;
  305. DUPNUM( tmp, b );
  306. destroynum( lasttmp );
  307. lasttmp=longtonum( 0, BASEX );
  308. while ( lessnum( tmp, rem ) )
  309. {
  310. destroynum( lasttmp );
  311. DUPNUM(lasttmp,tmp);
  312. addnum( &tmp, tmp, BASEX );
  313. digit *= 2;
  314. }
  315. if ( lessnum( rem, tmp ) )
  316. {
  317. // too far, back up...
  318. destroynum( tmp );
  319. digit /= 2;
  320. tmp=lasttmp;
  321. lasttmp=NULL;
  322. }
  323. tmp->sign *= -1;
  324. addnum( &rem, tmp, BASEX );
  325. destroynum( tmp );
  326. destroynum( lasttmp );
  327. *ptrc |= digit;
  328. }
  329. rem->exp++;
  330. ptrc--;
  331. }
  332. cdigits--;
  333. if ( MANT(c) != ++ptrc )
  334. {
  335. memcpy( MANT(c), ptrc, (int)(cdigits*sizeof(MANTTYPE)) );
  336. }
  337. if ( !cdigits )
  338. {
  339. // A zero, make sure no wierd exponents creep in
  340. c->exp = 0;
  341. c->cdigit = 1;
  342. }
  343. else
  344. {
  345. c->cdigit = cdigits;
  346. c->exp -= cdigits;
  347. // prevent different kinds of zeros, by stripping leading duplicate
  348. // zeroes. digits are in order of increasing significance.
  349. while ( c->cdigit > 1 && MANT(c)[c->cdigit-1] == 0 )
  350. {
  351. c->cdigit--;
  352. }
  353. }
  354. destroynum( rem );
  355. destroynum( *pa );
  356. *pa=c;
  357. }