PageRenderTime 26ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/otherlibs/num/bng.c

http://github.com/thelema/ocaml-community
C | 435 lines | 316 code | 33 blank | 86 comment | 103 complexity | 6139b4011479c96bfcd37bd5d0130478 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0
  1. /***********************************************************************/
  2. /* */
  3. /* OCaml */
  4. /* */
  5. /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
  6. /* */
  7. /* Copyright 2003 Institut National de Recherche en Informatique et */
  8. /* en Automatique. All rights reserved. This file is distributed */
  9. /* under the terms of the GNU Library General Public License, with */
  10. /* the special exception on linking described in file ../../LICENSE. */
  11. /* */
  12. /***********************************************************************/
  13. /* $Id$ */
  14. #include "bng.h"
  15. #include "config.h"
  16. #if defined(__GNUC__) && BNG_ASM_LEVEL > 0
  17. #if defined(BNG_ARCH_ia32)
  18. #include "bng_ia32.c"
  19. #elif defined(BNG_ARCH_amd64)
  20. #include "bng_amd64.c"
  21. #elif defined(BNG_ARCH_ppc)
  22. #include "bng_ppc.c"
  23. #elif defined (BNG_ARCH_alpha)
  24. #include "bng_alpha.c"
  25. #elif defined (BNG_ARCH_sparc)
  26. #include "bng_sparc.c"
  27. #elif defined (BNG_ARCH_mips)
  28. #include "bng_mips.c"
  29. #endif
  30. #endif
  31. #include "bng_digit.c"
  32. /**** Operations that cannot be overridden ****/
  33. /* Return number of leading zero bits in d */
  34. int bng_leading_zero_bits(bngdigit d)
  35. {
  36. int n = BNG_BITS_PER_DIGIT;
  37. #ifdef ARCH_SIXTYFOUR
  38. if ((d & 0xFFFFFFFF00000000L) != 0) { n -= 32; d = d >> 32; }
  39. #endif
  40. if ((d & 0xFFFF0000) != 0) { n -= 16; d = d >> 16; }
  41. if ((d & 0xFF00) != 0) { n -= 8; d = d >> 8; }
  42. if ((d & 0xF0) != 0) { n -= 4; d = d >> 4; }
  43. if ((d & 0xC) != 0) { n -= 2; d = d >> 2; }
  44. if ((d & 2) != 0) { n -= 1; d = d >> 1; }
  45. return n - d;
  46. }
  47. /* Complement the digits of {a,len} */
  48. void bng_complement(bng a/*[alen]*/, bngsize alen)
  49. {
  50. for (/**/; alen > 0; alen--, a++) *a = ~*a;
  51. }
  52. /* Return number of significant digits in {a,alen}. */
  53. bngsize bng_num_digits(bng a/*[alen]*/, bngsize alen)
  54. {
  55. while (1) {
  56. if (alen == 0) return 1;
  57. if (a[alen - 1] != 0) return alen;
  58. alen--;
  59. }
  60. }
  61. /* Return 0 if {a,alen} = {b,blen}
  62. -1 if {a,alen} < {b,blen}
  63. 1 if {a,alen} > {b,blen}. */
  64. int bng_compare(bng a/*[alen]*/, bngsize alen,
  65. bng b/*[blen]*/, bngsize blen)
  66. {
  67. bngdigit da, db;
  68. while (alen > 0 && a[alen-1] == 0) alen--;
  69. while (blen > 0 && b[blen-1] == 0) blen--;
  70. if (alen > blen) return 1;
  71. if (alen < blen) return -1;
  72. while (alen > 0) {
  73. alen--;
  74. da = a[alen];
  75. db = b[alen];
  76. if (da > db) return 1;
  77. if (da < db) return -1;
  78. }
  79. return 0;
  80. }
  81. /**** Generic definitions of the overridable operations ****/
  82. /* {a,alen} := {a, alen} + carry. Return carry out. */
  83. static bngcarry bng_generic_add_carry
  84. (bng a/*[alen]*/, bngsize alen, bngcarry carry)
  85. {
  86. if (carry == 0 || alen == 0) return carry;
  87. do {
  88. if (++(*a) != 0) return 0;
  89. a++;
  90. } while (--alen);
  91. return 1;
  92. }
  93. /* {a,alen} := {a,alen} + {b,blen} + carry. Return carry out.
  94. Require alen >= blen. */
  95. static bngcarry bng_generic_add
  96. (bng a/*[alen]*/, bngsize alen,
  97. bng b/*[blen]*/, bngsize blen,
  98. bngcarry carry)
  99. {
  100. alen -= blen;
  101. for (/**/; blen > 0; blen--, a++, b++) {
  102. BngAdd2Carry(*a, carry, *a, *b, carry);
  103. }
  104. if (carry == 0 || alen == 0) return carry;
  105. do {
  106. if (++(*a) != 0) return 0;
  107. a++;
  108. } while (--alen);
  109. return 1;
  110. }
  111. /* {a,alen} := {a, alen} - carry. Return carry out. */
  112. static bngcarry bng_generic_sub_carry
  113. (bng a/*[alen]*/, bngsize alen, bngcarry carry)
  114. {
  115. if (carry == 0 || alen == 0) return carry;
  116. do {
  117. if ((*a)-- != 0) return 0;
  118. a++;
  119. } while (--alen);
  120. return 1;
  121. }
  122. /* {a,alen} := {a,alen} - {b,blen} - carry. Return carry out.
  123. Require alen >= blen. */
  124. static bngcarry bng_generic_sub
  125. (bng a/*[alen]*/, bngsize alen,
  126. bng b/*[blen]*/, bngsize blen,
  127. bngcarry carry)
  128. {
  129. alen -= blen;
  130. for (/**/; blen > 0; blen--, a++, b++) {
  131. BngSub2Carry(*a, carry, *a, *b, carry);
  132. }
  133. if (carry == 0 || alen == 0) return carry;
  134. do {
  135. if ((*a)-- != 0) return 0;
  136. a++;
  137. } while (--alen);
  138. return 1;
  139. }
  140. /* {a,alen} := {a,alen} << shift.
  141. Return the bits shifted out of the most significant digit of a.
  142. Require 0 <= shift < BITS_PER_BNGDIGIT. */
  143. static bngdigit bng_generic_shift_left
  144. (bng a/*[alen]*/, bngsize alen,
  145. int shift)
  146. {
  147. int shift2 = BNG_BITS_PER_DIGIT - shift;
  148. bngdigit carry = 0;
  149. if (shift > 0) {
  150. for (/**/; alen > 0; alen--, a++) {
  151. bngdigit d = *a;
  152. *a = (d << shift) | carry;
  153. carry = d >> shift2;
  154. }
  155. }
  156. return carry;
  157. }
  158. /* {a,alen} := {a,alen} >> shift.
  159. Return the bits shifted out of the least significant digit of a.
  160. Require 0 <= shift < BITS_PER_BNGDIGIT. */
  161. static bngdigit bng_generic_shift_right
  162. (bng a/*[alen]*/, bngsize alen,
  163. int shift)
  164. {
  165. int shift2 = BNG_BITS_PER_DIGIT - shift;
  166. bngdigit carry = 0;
  167. if (shift > 0) {
  168. for (a = a + alen - 1; alen > 0; alen--, a--) {
  169. bngdigit d = *a;
  170. *a = (d >> shift) | carry;
  171. carry = d << shift2;
  172. }
  173. }
  174. return carry;
  175. }
  176. /* {a,alen} := {a,alen} + d * {b,blen}. Return carry out.
  177. Require alen >= blen. */
  178. static bngdigit bng_generic_mult_add_digit
  179. (bng a/*[alen]*/, bngsize alen,
  180. bng b/*[blen]*/, bngsize blen,
  181. bngdigit d)
  182. {
  183. bngdigit out, ph, pl;
  184. bngcarry carry;
  185. alen -= blen;
  186. for (out = 0; blen > 0; blen--, a++, b++) {
  187. bngdigit bd = *b;
  188. /* ph:pl = double-digit product of b's current digit and d */
  189. BngMult(ph, pl, bd, d);
  190. /* current digit of a += pl + out. Accumulate carries in ph. */
  191. BngAdd3(*a, ph, *a, pl, out);
  192. /* prepare out for next iteration */
  193. out = ph;
  194. }
  195. if (alen == 0) return out;
  196. /* current digit of a += out */
  197. BngAdd2(*a, carry, *a, out);
  198. a++;
  199. alen--;
  200. /* Propagate carry */
  201. if (carry == 0 || alen == 0) return carry;
  202. do {
  203. if (++(*a) != 0) return 0;
  204. a++;
  205. } while (--alen);
  206. return 1;
  207. }
  208. /* {a,alen} := {a,alen} - d * {b,blen}. Return carry out.
  209. Require alen >= blen. */
  210. static bngdigit bng_generic_mult_sub_digit
  211. (bng a/*[alen]*/, bngsize alen,
  212. bng b/*[blen]*/, bngsize blen,
  213. bngdigit d)
  214. {
  215. bngdigit out, ph, pl;
  216. bngcarry carry;
  217. alen -= blen;
  218. for (out = 0; blen > 0; blen--, a++, b++) {
  219. bngdigit bd = *b;
  220. /* ph:pl = double-digit product of b's current digit and d */
  221. BngMult(ph, pl, bd, d);
  222. /* current digit of a -= pl + out. Accumulate carrys in ph. */
  223. BngSub3(*a, ph, *a, pl, out);
  224. /* prepare out for next iteration */
  225. out = ph;
  226. }
  227. if (alen == 0) return out;
  228. /* current digit of a -= out */
  229. BngSub2(*a, carry, *a, out);
  230. a++;
  231. alen--;
  232. /* Propagate carry */
  233. if (carry == 0 || alen == 0) return carry;
  234. do {
  235. if ((*a)-- != 0) return 0;
  236. a++;
  237. } while (--alen);
  238. return 1;
  239. }
  240. /* {a,alen} := {a,alen} + {b,blen} * {c,clen}. Return carry out.
  241. Require alen >= blen + clen. */
  242. static bngcarry bng_generic_mult_add
  243. (bng a/*[alen]*/, bngsize alen,
  244. bng b/*[blen]*/, bngsize blen,
  245. bng c/*[clen]*/, bngsize clen)
  246. {
  247. bngcarry carry;
  248. for (carry = 0; clen > 0; clen--, c++, alen--, a++)
  249. carry += bng_mult_add_digit(a, alen, b, blen, *c);
  250. return carry;
  251. }
  252. /* {a,alen} := 2 * {a,alen} + {b,blen}^2. Return carry out.
  253. Require alen >= 2 * blen. */
  254. static bngcarry bng_generic_square_add
  255. (bng a/*[alen]*/, bngsize alen,
  256. bng b/*[blen]*/, bngsize blen)
  257. {
  258. bngcarry carry1, carry2;
  259. bngsize i, aofs;
  260. bngdigit ph, pl, d;
  261. /* Double products */
  262. for (carry1 = 0, i = 1; i < blen; i++) {
  263. aofs = 2 * i - 1;
  264. carry1 += bng_mult_add_digit(a + aofs, alen - aofs,
  265. b + i, blen - i, b[i - 1]);
  266. }
  267. /* Multiply by two */
  268. carry1 = (carry1 << 1) | bng_shift_left(a, alen, 1);
  269. /* Add square of digits */
  270. carry2 = 0;
  271. for (i = 0; i < blen; i++) {
  272. d = b[i];
  273. BngMult(ph, pl, d, d);
  274. BngAdd2Carry(*a, carry2, *a, pl, carry2);
  275. a++;
  276. BngAdd2Carry(*a, carry2, *a, ph, carry2);
  277. a++;
  278. }
  279. alen -= 2 * blen;
  280. if (alen > 0 && carry2 != 0) {
  281. do {
  282. if (++(*a) != 0) { carry2 = 0; break; }
  283. a++;
  284. } while (--alen);
  285. }
  286. return carry1 + carry2;
  287. }
  288. /* {a,len-1} := {b,len} / d. Return {b,len} modulo d.
  289. Require MSD of b < d.
  290. If BngDivNeedsNormalization is defined, require d normalized. */
  291. static bngdigit bng_generic_div_rem_norm_digit
  292. (bng a/*[len-1]*/, bng b/*[len]*/, bngsize len, bngdigit d)
  293. {
  294. bngdigit topdigit, quo, rem;
  295. intnat i;
  296. topdigit = b[len - 1];
  297. for (i = len - 2; i >= 0; i--) {
  298. /* Divide topdigit:current digit of numerator by d */
  299. BngDiv(quo, rem, topdigit, b[i], d);
  300. /* Quotient is current digit of result */
  301. a[i] = quo;
  302. /* Iterate with topdigit = remainder */
  303. topdigit = rem;
  304. }
  305. return topdigit;
  306. }
  307. #ifdef BngDivNeedsNormalization
  308. /* {a,len-1} := {b,len} / d. Return {b,len} modulo d.
  309. Require MSD of b < d. */
  310. static bngdigit bng_generic_div_rem_digit
  311. (bng a/*[len-1]*/, bng b/*[len]*/, bngsize len, bngdigit d)
  312. {
  313. bngdigit rem;
  314. int shift;
  315. /* Normalize d and b */
  316. shift = bng_leading_zero_bits(d);
  317. d <<= shift;
  318. bng_shift_left(b, len, shift);
  319. /* Do the division */
  320. rem = bng_div_rem_norm_digit(a, b, len, d);
  321. /* Undo normalization on b and remainder */
  322. bng_shift_right(b, len, shift);
  323. return rem >> shift;
  324. }
  325. #endif
  326. /* {n+dlen, nlen-dlen} := {n,nlen} / {d, dlen}.
  327. {n, dlen} := {n,nlen} modulo {d, dlen}.
  328. Require nlen > dlen and MSD of n < MSD of d.
  329. (This implies MSD of d > 0). */
  330. static void bng_generic_div_rem
  331. (bng n/*[nlen]*/, bngsize nlen,
  332. bng d/*[dlen]*/, bngsize dlen)
  333. {
  334. bngdigit topden, quo, rem;
  335. int shift;
  336. bngsize i, j;
  337. /* Normalize d */
  338. shift = bng_leading_zero_bits(d[dlen - 1]);
  339. /* Note that no bits of n are lost by the following shift,
  340. since n[nlen-1] < d[dlen-1] */
  341. bng_shift_left(n, nlen, shift);
  342. bng_shift_left(d, dlen, shift);
  343. /* Special case if d is just one digit */
  344. if (dlen == 1) {
  345. *n = bng_div_rem_norm_digit(n + 1, n, nlen, *d);
  346. } else {
  347. topden = d[dlen - 1];
  348. /* Long division */
  349. for (j = nlen - 1; j >= dlen; j--) {
  350. i = j - dlen;
  351. /* At this point:
  352. - the current numerator is n[j] : ...................... : n[0]
  353. - to be subtracted quo times: d[dlen-1] : ... : d[0] : 0... : 0
  354. (there are i zeroes at the end) */
  355. /* Under-estimate the next digit of the quotient (quo) */
  356. if (topden + 1 == 0)
  357. quo = n[j];
  358. else
  359. BngDiv(quo, rem, n[j], n[j - 1], topden + 1);
  360. /* Subtract d * quo (shifted i places) from numerator */
  361. n[j] -= bng_mult_sub_digit(n + i, dlen, d, dlen, quo);
  362. /* Adjust if necessary */
  363. while (n[j] != 0 || bng_compare(n + i, dlen, d, dlen) >= 0) {
  364. /* Numerator is still bigger than shifted divisor.
  365. Increment quotient and subtract shifted divisor. */
  366. quo++;
  367. n[j] -= bng_sub(n + i, dlen, d, dlen, 0);
  368. }
  369. /* Store quotient digit */
  370. n[j] = quo;
  371. }
  372. }
  373. /* Undo normalization on remainder and divisor */
  374. bng_shift_right(n, dlen, shift);
  375. bng_shift_right(d, dlen, shift);
  376. }
  377. /**** Construction of the table of operations ****/
  378. struct bng_operations bng_ops = {
  379. bng_generic_add_carry,
  380. bng_generic_add,
  381. bng_generic_sub_carry,
  382. bng_generic_sub,
  383. bng_generic_shift_left,
  384. bng_generic_shift_right,
  385. bng_generic_mult_add_digit,
  386. bng_generic_mult_sub_digit,
  387. bng_generic_mult_add,
  388. bng_generic_square_add,
  389. bng_generic_div_rem_norm_digit,
  390. #ifdef BngDivNeedsNormalization
  391. bng_generic_div_rem_digit,
  392. #else
  393. bng_generic_div_rem_norm_digit,
  394. #endif
  395. bng_generic_div_rem
  396. };
  397. void bng_init(void)
  398. {
  399. #ifdef BNG_SETUP_OPS
  400. BNG_SETUP_OPS;
  401. #endif
  402. }