glplib02.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /* glplib02.c (64-bit 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. * NAME
  27. *
  28. * xlset - expand integer to long integer
  29. *
  30. * SYNOPSIS
  31. *
  32. * #include "glplib.h"
  33. * glp_long xlset(int x);
  34. *
  35. * RETURNS
  36. *
  37. * The routine xlset returns x expanded to long integer. */
  38. glp_long xlset(int x)
  39. { glp_long t;
  40. t.lo = x, t.hi = (x >= 0 ? 0 : -1);
  41. return t;
  42. }
  43. /***********************************************************************
  44. * NAME
  45. *
  46. * xlneg - negate long integer
  47. *
  48. * SYNOPSIS
  49. *
  50. * #include "glplib.h"
  51. * glp_long xlneg(glp_long x);
  52. *
  53. * RETURNS
  54. *
  55. * The routine xlneg returns the difference 0 - x. */
  56. glp_long xlneg(glp_long x)
  57. { if (x.lo)
  58. x.lo = - x.lo, x.hi = ~x.hi;
  59. else
  60. x.hi = - x.hi;
  61. return x;
  62. }
  63. /***********************************************************************
  64. * NAME
  65. *
  66. * xladd - add long integers
  67. *
  68. * SYNOPSIS
  69. *
  70. * #include "glplib.h"
  71. * glp_long xladd(glp_long x, glp_long y);
  72. *
  73. * RETURNS
  74. *
  75. * The routine xladd returns the sum x + y. */
  76. glp_long xladd(glp_long x, glp_long y)
  77. { if ((unsigned int)x.lo <= 0xFFFFFFFF - (unsigned int)y.lo)
  78. x.lo += y.lo, x.hi += y.hi;
  79. else
  80. x.lo += y.lo, x.hi += y.hi + 1;
  81. return x;
  82. }
  83. /***********************************************************************
  84. * NAME
  85. *
  86. * xlsub - subtract long integers
  87. *
  88. * SYNOPSIS
  89. *
  90. * #include "glplib.h"
  91. * glp_long xlsub(glp_long x, glp_long y);
  92. *
  93. * RETURNS
  94. *
  95. * The routine xlsub returns the difference x - y. */
  96. glp_long xlsub(glp_long x, glp_long y)
  97. { return
  98. xladd(x, xlneg(y));
  99. }
  100. /***********************************************************************
  101. * NAME
  102. *
  103. * xlcmp - compare long integers
  104. *
  105. * SYNOPSIS
  106. *
  107. * #include "glplib.h"
  108. * int xlcmp(glp_long x, glp_long y);
  109. *
  110. * RETURNS
  111. *
  112. * The routine xlcmp returns the sign of the difference x - y. */
  113. int xlcmp(glp_long x, glp_long y)
  114. { if (x.hi >= 0 && y.hi < 0) return +1;
  115. if (x.hi < 0 && y.hi >= 0) return -1;
  116. if ((unsigned int)x.hi < (unsigned int)y.hi) return -1;
  117. if ((unsigned int)x.hi > (unsigned int)y.hi) return +1;
  118. if ((unsigned int)x.lo < (unsigned int)y.lo) return -1;
  119. if ((unsigned int)x.lo > (unsigned int)y.lo) return +1;
  120. return 0;
  121. }
  122. /***********************************************************************
  123. * NAME
  124. *
  125. * xlmul - multiply long integers
  126. *
  127. * SYNOPSIS
  128. *
  129. * #include "glplib.h"
  130. * glp_long xlmul(glp_long x, glp_long y);
  131. *
  132. * RETURNS
  133. *
  134. * The routine xlmul returns the product x * y. */
  135. glp_long xlmul(glp_long x, glp_long y)
  136. { unsigned short xx[8], yy[4];
  137. xx[4] = (unsigned short)x.lo;
  138. xx[5] = (unsigned short)(x.lo >> 16);
  139. xx[6] = (unsigned short)x.hi;
  140. xx[7] = (unsigned short)(x.hi >> 16);
  141. yy[0] = (unsigned short)y.lo;
  142. yy[1] = (unsigned short)(y.lo >> 16);
  143. yy[2] = (unsigned short)y.hi;
  144. yy[3] = (unsigned short)(y.hi >> 16);
  145. bigmul(4, 4, xx, yy);
  146. x.lo = (unsigned int)xx[0] | ((unsigned int)xx[1] << 16);
  147. x.hi = (unsigned int)xx[2] | ((unsigned int)xx[3] << 16);
  148. return x;
  149. }
  150. /***********************************************************************
  151. * NAME
  152. *
  153. * xldiv - divide long integers
  154. *
  155. * SYNOPSIS
  156. *
  157. * #include "glplib.h"
  158. * glp_ldiv xldiv(glp_long x, glp_long y);
  159. *
  160. * RETURNS
  161. *
  162. * The routine xldiv returns a structure of type glp_ldiv containing
  163. * members quot (the quotient) and rem (the remainder), both of type
  164. * glp_long. */
  165. glp_ldiv xldiv(glp_long x, glp_long y)
  166. { glp_ldiv t;
  167. int m, sx, sy;
  168. unsigned short xx[8], yy[4];
  169. /* sx := sign(x) */
  170. sx = (x.hi < 0);
  171. /* sy := sign(y) */
  172. sy = (y.hi < 0);
  173. /* x := |x| */
  174. if (sx) x = xlneg(x);
  175. /* y := |y| */
  176. if (sy) y = xlneg(y);
  177. /* compute x div y and x mod y */
  178. xx[0] = (unsigned short)x.lo;
  179. xx[1] = (unsigned short)(x.lo >> 16);
  180. xx[2] = (unsigned short)x.hi;
  181. xx[3] = (unsigned short)(x.hi >> 16);
  182. yy[0] = (unsigned short)y.lo;
  183. yy[1] = (unsigned short)(y.lo >> 16);
  184. yy[2] = (unsigned short)y.hi;
  185. yy[3] = (unsigned short)(y.hi >> 16);
  186. if (yy[3])
  187. m = 4;
  188. else if (yy[2])
  189. m = 3;
  190. else if (yy[1])
  191. m = 2;
  192. else if (yy[0])
  193. m = 1;
  194. else
  195. xerror("xldiv: divide by zero\n");
  196. bigdiv(4 - m, m, xx, yy);
  197. /* remainder in x[0], x[1], ..., x[m-1] */
  198. t.rem.lo = (unsigned int)xx[0], t.rem.hi = 0;
  199. if (m >= 2) t.rem.lo |= (unsigned int)xx[1] << 16;
  200. if (m >= 3) t.rem.hi = (unsigned int)xx[2];
  201. if (m >= 4) t.rem.hi |= (unsigned int)xx[3] << 16;
  202. if (sx) t.rem = xlneg(t.rem);
  203. /* quotient in x[m], x[m+1], ..., x[4] */
  204. t.quot.lo = (unsigned int)xx[m], t.quot.hi = 0;
  205. if (m <= 3) t.quot.lo |= (unsigned int)xx[m+1] << 16;
  206. if (m <= 2) t.quot.hi = (unsigned int)xx[m+2];
  207. if (m <= 1) t.quot.hi |= (unsigned int)xx[m+3] << 16;
  208. if (sx ^ sy) t.quot = xlneg(t.quot);
  209. return t;
  210. }
  211. /***********************************************************************
  212. * NAME
  213. *
  214. * xltod - convert long integer to double
  215. *
  216. * SYNOPSIS
  217. *
  218. * #include "glplib.h"
  219. * double xltod(glp_long x);
  220. *
  221. * RETURNS
  222. *
  223. * The routine xltod returns x converted to double. */
  224. double xltod(glp_long x)
  225. { double s, z;
  226. if (x.hi >= 0)
  227. s = +1.0;
  228. else
  229. s = -1.0, x = xlneg(x);
  230. if (x.hi >= 0)
  231. z = 4294967296.0 * (double)x.hi + (double)(unsigned int)x.lo;
  232. else
  233. { xassert(x.hi == 0x80000000 && x.lo == 0x00000000);
  234. z = 9223372036854775808.0; /* 2^63 */
  235. }
  236. return s * z;
  237. }
  238. char *xltoa(glp_long x, char *s)
  239. { /* convert long integer to character string */
  240. static const char *d = "0123456789";
  241. glp_ldiv t;
  242. int neg, len;
  243. if (x.hi >= 0)
  244. neg = 0;
  245. else
  246. neg = 1, x = xlneg(x);
  247. if (x.hi >= 0)
  248. { len = 0;
  249. while (!(x.hi == 0 && x.lo == 0))
  250. { t = xldiv(x, xlset(10));
  251. xassert(0 <= t.rem.lo && t.rem.lo <= 9);
  252. s[len++] = d[t.rem.lo];
  253. x = t.quot;
  254. }
  255. if (len == 0) s[len++] = d[0];
  256. if (neg) s[len++] = '-';
  257. s[len] = '\0';
  258. strrev(s);
  259. }
  260. else
  261. strcpy(s, "-9223372036854775808"); /* -2^63 */
  262. return s;
  263. }
  264. /**********************************************************************/
  265. #if 0
  266. #include "glprng.h"
  267. #define N_TEST 1000000
  268. /* number of tests */
  269. static glp_long myrand(RNG *rand)
  270. { glp_long x;
  271. int k;
  272. k = rng_unif_rand(rand, 4);
  273. xassert(0 <= k && k <= 3);
  274. x.lo = rng_unif_rand(rand, 65536);
  275. if (k == 1 || k == 3)
  276. { x.lo <<= 16;
  277. x.lo += rng_unif_rand(rand, 65536);
  278. }
  279. if (k <= 1)
  280. x.hi = 0;
  281. else
  282. x.hi = rng_unif_rand(rand, 65536);
  283. if (k == 3)
  284. { x.hi <<= 16;
  285. x.hi += rng_unif_rand(rand, 65536);
  286. }
  287. if (rng_unif_rand(rand, 2)) x = xlneg(x);
  288. return x;
  289. }
  290. int main(void)
  291. { RNG *rand;
  292. glp_long x, y;
  293. glp_ldiv z;
  294. int test;
  295. rand = rng_create_rand();
  296. for (test = 1; test <= N_TEST; test++)
  297. { x = myrand(rand);
  298. y = myrand(rand);
  299. if (y.lo == 0 && y.hi == 0) y.lo = 1;
  300. /* z.quot := x div y, z.rem := x mod y */
  301. z = xldiv(x, y);
  302. /* x must be equal to y * z.quot + z.rem */
  303. xassert(xlcmp(x, xladd(xlmul(y, z.quot), z.rem)) == 0);
  304. }
  305. xprintf("%d tests successfully passed\n", N_TEST);
  306. rng_delete_rand(rand);
  307. return 0;
  308. }
  309. #endif
  310. /* eof */