mpvecdigmuladd.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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. #define LO(x) ((x) & ((1<<(Dbits/2))-1))
  13. #define HI(x) ((x) >> (Dbits/2))
  14. static void
  15. mpdigmul(mpdigit a, mpdigit b, mpdigit *p)
  16. {
  17. mpdigit x, ah, al, bh, bl, p1, p2, p3, p4;
  18. int carry;
  19. // half digits
  20. ah = HI(a);
  21. al = LO(a);
  22. bh = HI(b);
  23. bl = LO(b);
  24. // partial products
  25. p1 = ah*bl;
  26. p2 = bh*al;
  27. p3 = bl*al;
  28. p4 = ah*bh;
  29. // p = ((p1+p2)<<(Dbits/2)) + (p4<<Dbits) + p3
  30. carry = 0;
  31. x = p1<<(Dbits/2);
  32. p3 += x;
  33. if(p3 < x)
  34. carry++;
  35. x = p2<<(Dbits/2);
  36. p3 += x;
  37. if(p3 < x)
  38. carry++;
  39. p4 += carry + HI(p1) + HI(p2); // can't carry out of the high digit
  40. p[0] = p3;
  41. p[1] = p4;
  42. }
  43. // prereq: p must have room for n+1 digits
  44. void
  45. mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
  46. {
  47. int i;
  48. mpdigit carry, x, y, part[2];
  49. carry = 0;
  50. part[1] = 0;
  51. for(i = 0; i < n; i++){
  52. x = part[1] + carry;
  53. if(x < carry)
  54. carry = 1;
  55. else
  56. carry = 0;
  57. y = *p;
  58. mpdigmul(*b++, m, part);
  59. x += part[0];
  60. if(x < part[0])
  61. carry++;
  62. x += y;
  63. if(x < y)
  64. carry++;
  65. *p++ = x;
  66. }
  67. *p = part[1] + carry;
  68. }
  69. // prereq: p must have room for n+1 digits
  70. int
  71. mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
  72. {
  73. int i;
  74. mpdigit x, y, part[2], borrow;
  75. borrow = 0;
  76. part[1] = 0;
  77. for(i = 0; i < n; i++){
  78. x = *p;
  79. y = x - borrow;
  80. if(y > x)
  81. borrow = 1;
  82. else
  83. borrow = 0;
  84. x = part[1];
  85. mpdigmul(*b++, m, part);
  86. x += part[0];
  87. if(x < part[0])
  88. borrow++;
  89. x = y - x;
  90. if(x > y)
  91. borrow++;
  92. *p++ = x;
  93. }
  94. x = *p;
  95. y = x - borrow - part[1];
  96. *p = y;
  97. if(y > x)
  98. return -1;
  99. else
  100. return 1;
  101. }