mpdiv.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "os.h"
  10. #include <mp.h>
  11. #include "dat.h"
  12. // division ala knuth, seminumerical algorithms, pp 237-238
  13. // the numbers are stored backwards to what knuth expects so j
  14. // counts down rather than up.
  15. void
  16. mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder)
  17. {
  18. int j, s, vn, sign;
  19. mpdigit qd, *up, *vp, *qp;
  20. mpint *u, *v, *t;
  21. // divide bv zero
  22. if(divisor->top == 0)
  23. abort();
  24. // quick check
  25. if(mpmagcmp(dividend, divisor) < 0){
  26. if(remainder != nil)
  27. mpassign(dividend, remainder);
  28. if(quotient != nil)
  29. mpassign(mpzero, quotient);
  30. return;
  31. }
  32. // D1: shift until divisor, v, has hi bit set (needed to make trial
  33. // divisor accurate)
  34. qd = divisor->p[divisor->top-1];
  35. for(s = 0; (qd & mpdighi) == 0; s++)
  36. qd <<= 1;
  37. u = mpnew((dividend->top+2)*Dbits + s);
  38. if(s == 0 && divisor != quotient && divisor != remainder) {
  39. mpassign(dividend, u);
  40. v = divisor;
  41. } else {
  42. mpleft(dividend, s, u);
  43. v = mpnew(divisor->top*Dbits);
  44. mpleft(divisor, s, v);
  45. }
  46. up = u->p+u->top-1;
  47. vp = v->p+v->top-1;
  48. vn = v->top;
  49. // D1a: make sure high digit of dividend is less than high digit of divisor
  50. if(*up >= *vp){
  51. *++up = 0;
  52. u->top++;
  53. }
  54. // storage for multiplies
  55. t = mpnew(4*Dbits);
  56. qp = nil;
  57. if(quotient != nil){
  58. mpbits(quotient, (u->top - v->top)*Dbits);
  59. quotient->top = u->top - v->top;
  60. qp = quotient->p+quotient->top-1;
  61. }
  62. // D2, D7: loop on length of dividend
  63. for(j = u->top; j > vn; j--){
  64. // D3: calculate trial divisor
  65. mpdigdiv(up-1, *vp, &qd);
  66. // D3a: rule out trial divisors 2 greater than real divisor
  67. if(vn > 1) for(;;){
  68. memset(t->p, 0, 3*Dbytes); // mpvecdigmuladd adds to what's there
  69. mpvecdigmuladd(vp-1, 2, qd, t->p);
  70. if(mpveccmp(t->p, 3, up-2, 3) > 0)
  71. qd--;
  72. else
  73. break;
  74. }
  75. // D4: u -= v*qd << j*Dbits
  76. sign = mpvecdigmulsub(v->p, vn, qd, up-vn);
  77. if(sign < 0){
  78. // D6: trial divisor was too high, add back borrowed
  79. // value and decrease divisor
  80. mpvecadd(up-vn, vn+1, v->p, vn, up-vn);
  81. qd--;
  82. }
  83. // D5: save quotient digit
  84. if(qp != nil)
  85. *qp-- = qd;
  86. // push top of u down one
  87. u->top--;
  88. *up-- = 0;
  89. }
  90. if(qp != nil){
  91. mpnorm(quotient);
  92. if(dividend->sign != divisor->sign)
  93. quotient->sign = -1;
  94. }
  95. if(remainder != nil){
  96. mpright(u, s, remainder); // u is the remainder shifted
  97. remainder->sign = dividend->sign;
  98. }
  99. mpfree(t);
  100. mpfree(u);
  101. if(v != divisor)
  102. mpfree(v);
  103. }