glplib01.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /* glplib01.c (bignum arithmetic) */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  6. * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  7. * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  8. * E-mail: <mao@gnu.org>.
  9. *
  10. * GLPK is free software: you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  18. * License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  22. ***********************************************************************/
  23. #include "glpenv.h"
  24. #include "glplib.h"
  25. /***********************************************************************
  26. * Two routines below are intended to multiply and divide unsigned
  27. * integer numbers of arbitrary precision.
  28. *
  29. * The routines assume that an unsigned integer number is represented in
  30. * the positional numeral system with the base 2^16 = 65536, i.e. each
  31. * "digit" of the number is in the range [0, 65535] and represented as
  32. * a 16-bit value of the unsigned short type. In other words, a number x
  33. * has the following representation:
  34. *
  35. * n-1
  36. * x = sum d[j] * 65536^j,
  37. * j=0
  38. *
  39. * where n is the number of places (positions), and d[j] is j-th "digit"
  40. * of x, 0 <= d[j] <= 65535.
  41. ***********************************************************************/
  42. /***********************************************************************
  43. * NAME
  44. *
  45. * bigmul - multiply unsigned integer numbers of arbitrary precision
  46. *
  47. * SYNOPSIS
  48. *
  49. * #include "glplib.h"
  50. * void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
  51. *
  52. * DESCRIPTION
  53. *
  54. * The routine bigmul multiplies unsigned integer numbers of arbitrary
  55. * precision.
  56. *
  57. * n is the number of digits of multiplicand, n >= 1;
  58. *
  59. * m is the number of digits of multiplier, m >= 1;
  60. *
  61. * x is an array containing digits of the multiplicand in elements
  62. * x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are
  63. * ignored on entry.
  64. *
  65. * y is an array containing digits of the multiplier in elements y[0],
  66. * y[1], ..., y[m-1].
  67. *
  68. * On exit digits of the product are stored in elements x[0], x[1], ...,
  69. * x[n+m-1]. The array y is not changed. */
  70. void bigmul(int n, int m, unsigned short x[], unsigned short y[])
  71. { int i, j;
  72. unsigned int t;
  73. xassert(n >= 1);
  74. xassert(m >= 1);
  75. for (j = 0; j < m; j++) x[j] = 0;
  76. for (i = 0; i < n; i++)
  77. { if (x[i+m])
  78. { t = 0;
  79. for (j = 0; j < m; j++)
  80. { t += (unsigned int)x[i+m] * (unsigned int)y[j] +
  81. (unsigned int)x[i+j];
  82. x[i+j] = (unsigned short)t;
  83. t >>= 16;
  84. }
  85. x[i+m] = (unsigned short)t;
  86. }
  87. }
  88. return;
  89. }
  90. /***********************************************************************
  91. * NAME
  92. *
  93. * bigdiv - divide unsigned integer numbers of arbitrary precision
  94. *
  95. * SYNOPSIS
  96. *
  97. * #include "glplib.h"
  98. * void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
  99. *
  100. * DESCRIPTION
  101. *
  102. * The routine bigdiv divides one unsigned integer number of arbitrary
  103. * precision by another with the algorithm described in [1].
  104. *
  105. * n is the difference between the number of digits of dividend and the
  106. * number of digits of divisor, n >= 0.
  107. *
  108. * m is the number of digits of divisor, m >= 1.
  109. *
  110. * x is an array containing digits of the dividend in elements x[0],
  111. * x[1], ..., x[n+m-1].
  112. *
  113. * y is an array containing digits of the divisor in elements y[0],
  114. * y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero.
  115. *
  116. * On exit n+1 digits of the quotient are stored in elements x[m],
  117. * x[m+1], ..., x[n+m], and m digits of the remainder are stored in
  118. * elements x[0], x[1], ..., x[m-1]. The array y is changed but then
  119. * restored.
  120. *
  121. * REFERENCES
  122. *
  123. * 1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical
  124. * Algorithms. Stanford University, 1969. */
  125. void bigdiv(int n, int m, unsigned short x[], unsigned short y[])
  126. { int i, j;
  127. unsigned int t;
  128. unsigned short d, q, r;
  129. xassert(n >= 0);
  130. xassert(m >= 1);
  131. xassert(y[m-1] != 0);
  132. /* special case when divisor has the only digit */
  133. if (m == 1)
  134. { d = 0;
  135. for (i = n; i >= 0; i--)
  136. { t = ((unsigned int)d << 16) + (unsigned int)x[i];
  137. x[i+1] = (unsigned short)(t / y[0]);
  138. d = (unsigned short)(t % y[0]);
  139. }
  140. x[0] = d;
  141. goto done;
  142. }
  143. /* multiply dividend and divisor by a normalizing coefficient in
  144. order to provide the condition y[m-1] >= base / 2 */
  145. d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1));
  146. if (d == 1)
  147. x[n+m] = 0;
  148. else
  149. { t = 0;
  150. for (i = 0; i < n+m; i++)
  151. { t += (unsigned int)x[i] * (unsigned int)d;
  152. x[i] = (unsigned short)t;
  153. t >>= 16;
  154. }
  155. x[n+m] = (unsigned short)t;
  156. t = 0;
  157. for (j = 0; j < m; j++)
  158. { t += (unsigned int)y[j] * (unsigned int)d;
  159. y[j] = (unsigned short)t;
  160. t >>= 16;
  161. }
  162. }
  163. /* main loop */
  164. for (i = n; i >= 0; i--)
  165. { /* estimate and correct the current digit of quotient */
  166. if (x[i+m] < y[m-1])
  167. { t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1];
  168. q = (unsigned short)(t / (unsigned int)y[m-1]);
  169. r = (unsigned short)(t % (unsigned int)y[m-1]);
  170. if (q == 0) goto putq; else goto test;
  171. }
  172. q = 0;
  173. r = x[i+m-1];
  174. decr: q--; /* if q = 0 then q-- = 0xFFFF */
  175. t = (unsigned int)r + (unsigned int)y[m-1];
  176. r = (unsigned short)t;
  177. if (t > 0xFFFF) goto msub;
  178. test: t = (unsigned int)y[m-2] * (unsigned int)q;
  179. if ((unsigned short)(t >> 16) > r) goto decr;
  180. if ((unsigned short)(t >> 16) < r) goto msub;
  181. if ((unsigned short)t > x[i+m-2]) goto decr;
  182. msub: /* now subtract divisor multiplied by the current digit of
  183. quotient from the current dividend */
  184. if (q == 0) goto putq;
  185. t = 0;
  186. for (j = 0; j < m; j++)
  187. { t += (unsigned int)y[j] * (unsigned int)q;
  188. if (x[i+j] < (unsigned short)t) t += 0x10000;
  189. x[i+j] -= (unsigned short)t;
  190. t >>= 16;
  191. }
  192. if (x[i+m] >= (unsigned short)t) goto putq;
  193. /* perform correcting addition, because the current digit of
  194. quotient is greater by one than its correct value */
  195. q--;
  196. t = 0;
  197. for (j = 0; j < m; j++)
  198. { t += (unsigned int)x[i+j] + (unsigned int)y[j];
  199. x[i+j] = (unsigned short)t;
  200. t >>= 16;
  201. }
  202. putq: /* store the current digit of quotient */
  203. x[i+m] = q;
  204. }
  205. /* divide divisor and remainder by the normalizing coefficient in
  206. order to restore their original values */
  207. if (d > 1)
  208. { t = 0;
  209. for (i = m-1; i >= 0; i--)
  210. { t = (t << 16) + (unsigned int)x[i];
  211. x[i] = (unsigned short)(t / (unsigned int)d);
  212. t %= (unsigned int)d;
  213. }
  214. t = 0;
  215. for (j = m-1; j >= 0; j--)
  216. { t = (t << 16) + (unsigned int)y[j];
  217. y[j] = (unsigned short)(t / (unsigned int)d);
  218. t %= (unsigned int)d;
  219. }
  220. }
  221. done: return;
  222. }
  223. /**********************************************************************/
  224. #if 0
  225. #include <assert.h>
  226. #include <stdio.h>
  227. #include <stdlib.h>
  228. #include "glprng.h"
  229. #define N_MAX 7
  230. /* maximal number of digits in multiplicand */
  231. #define M_MAX 5
  232. /* maximal number of digits in multiplier */
  233. #define N_TEST 1000000
  234. /* number of tests */
  235. int main(void)
  236. { RNG *rand;
  237. int d, j, n, m, test;
  238. unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX];
  239. rand = rng_create_rand();
  240. for (test = 1; test <= N_TEST; test++)
  241. { /* x[0,...,n-1] := multiplicand */
  242. n = 1 + rng_unif_rand(rand, N_MAX-1);
  243. assert(1 <= n && n <= N_MAX);
  244. for (j = 0; j < n; j++)
  245. { d = rng_unif_rand(rand, 65536);
  246. assert(0 <= d && d <= 65535);
  247. x[j] = (unsigned short)d;
  248. }
  249. /* y[0,...,m-1] := multiplier */
  250. m = 1 + rng_unif_rand(rand, M_MAX-1);
  251. assert(1 <= m && m <= M_MAX);
  252. for (j = 0; j < m; j++)
  253. { d = rng_unif_rand(rand, 65536);
  254. assert(0 <= d && d <= 65535);
  255. y[j] = (unsigned short)d;
  256. }
  257. if (y[m-1] == 0) y[m-1] = 1;
  258. /* z[0,...,n+m-1] := x * y */
  259. for (j = 0; j < n; j++) z[m+j] = x[j];
  260. bigmul(n, m, z, y);
  261. /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */
  262. bigdiv(n, m, z, y);
  263. /* z mod y must be 0 */
  264. for (j = 0; j < m; j++) assert(z[j] == 0);
  265. /* z div y must be x */
  266. for (j = 0; j < n; j++) assert(z[m+j] == x[j]);
  267. }
  268. fprintf(stderr, "%d tests successfully passed\n", N_TEST);
  269. rng_delete_rand(rand);
  270. return 0;
  271. }
  272. #endif
  273. /* eof */