rev |
line source |
alpar@9
|
1 /* glplib02.c (64-bit arithmetic) */
|
alpar@9
|
2
|
alpar@9
|
3 /***********************************************************************
|
alpar@9
|
4 * This code is part of GLPK (GNU Linear Programming Kit).
|
alpar@9
|
5 *
|
alpar@9
|
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
alpar@9
|
7 * 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
|
alpar@9
|
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
|
alpar@9
|
9 * E-mail: <mao@gnu.org>.
|
alpar@9
|
10 *
|
alpar@9
|
11 * GLPK is free software: you can redistribute it and/or modify it
|
alpar@9
|
12 * under the terms of the GNU General Public License as published by
|
alpar@9
|
13 * the Free Software Foundation, either version 3 of the License, or
|
alpar@9
|
14 * (at your option) any later version.
|
alpar@9
|
15 *
|
alpar@9
|
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT
|
alpar@9
|
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
alpar@9
|
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
alpar@9
|
19 * License for more details.
|
alpar@9
|
20 *
|
alpar@9
|
21 * You should have received a copy of the GNU General Public License
|
alpar@9
|
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
alpar@9
|
23 ***********************************************************************/
|
alpar@9
|
24
|
alpar@9
|
25 #include "glpenv.h"
|
alpar@9
|
26 #include "glplib.h"
|
alpar@9
|
27
|
alpar@9
|
28 /***********************************************************************
|
alpar@9
|
29 * NAME
|
alpar@9
|
30 *
|
alpar@9
|
31 * xlset - expand integer to long integer
|
alpar@9
|
32 *
|
alpar@9
|
33 * SYNOPSIS
|
alpar@9
|
34 *
|
alpar@9
|
35 * #include "glplib.h"
|
alpar@9
|
36 * glp_long xlset(int x);
|
alpar@9
|
37 *
|
alpar@9
|
38 * RETURNS
|
alpar@9
|
39 *
|
alpar@9
|
40 * The routine xlset returns x expanded to long integer. */
|
alpar@9
|
41
|
alpar@9
|
42 glp_long xlset(int x)
|
alpar@9
|
43 { glp_long t;
|
alpar@9
|
44 t.lo = x, t.hi = (x >= 0 ? 0 : -1);
|
alpar@9
|
45 return t;
|
alpar@9
|
46 }
|
alpar@9
|
47
|
alpar@9
|
48 /***********************************************************************
|
alpar@9
|
49 * NAME
|
alpar@9
|
50 *
|
alpar@9
|
51 * xlneg - negate long integer
|
alpar@9
|
52 *
|
alpar@9
|
53 * SYNOPSIS
|
alpar@9
|
54 *
|
alpar@9
|
55 * #include "glplib.h"
|
alpar@9
|
56 * glp_long xlneg(glp_long x);
|
alpar@9
|
57 *
|
alpar@9
|
58 * RETURNS
|
alpar@9
|
59 *
|
alpar@9
|
60 * The routine xlneg returns the difference 0 - x. */
|
alpar@9
|
61
|
alpar@9
|
62 glp_long xlneg(glp_long x)
|
alpar@9
|
63 { if (x.lo)
|
alpar@9
|
64 x.lo = - x.lo, x.hi = ~x.hi;
|
alpar@9
|
65 else
|
alpar@9
|
66 x.hi = - x.hi;
|
alpar@9
|
67 return x;
|
alpar@9
|
68 }
|
alpar@9
|
69
|
alpar@9
|
70 /***********************************************************************
|
alpar@9
|
71 * NAME
|
alpar@9
|
72 *
|
alpar@9
|
73 * xladd - add long integers
|
alpar@9
|
74 *
|
alpar@9
|
75 * SYNOPSIS
|
alpar@9
|
76 *
|
alpar@9
|
77 * #include "glplib.h"
|
alpar@9
|
78 * glp_long xladd(glp_long x, glp_long y);
|
alpar@9
|
79 *
|
alpar@9
|
80 * RETURNS
|
alpar@9
|
81 *
|
alpar@9
|
82 * The routine xladd returns the sum x + y. */
|
alpar@9
|
83
|
alpar@9
|
84 glp_long xladd(glp_long x, glp_long y)
|
alpar@9
|
85 { if ((unsigned int)x.lo <= 0xFFFFFFFF - (unsigned int)y.lo)
|
alpar@9
|
86 x.lo += y.lo, x.hi += y.hi;
|
alpar@9
|
87 else
|
alpar@9
|
88 x.lo += y.lo, x.hi += y.hi + 1;
|
alpar@9
|
89 return x;
|
alpar@9
|
90 }
|
alpar@9
|
91
|
alpar@9
|
92 /***********************************************************************
|
alpar@9
|
93 * NAME
|
alpar@9
|
94 *
|
alpar@9
|
95 * xlsub - subtract long integers
|
alpar@9
|
96 *
|
alpar@9
|
97 * SYNOPSIS
|
alpar@9
|
98 *
|
alpar@9
|
99 * #include "glplib.h"
|
alpar@9
|
100 * glp_long xlsub(glp_long x, glp_long y);
|
alpar@9
|
101 *
|
alpar@9
|
102 * RETURNS
|
alpar@9
|
103 *
|
alpar@9
|
104 * The routine xlsub returns the difference x - y. */
|
alpar@9
|
105
|
alpar@9
|
106 glp_long xlsub(glp_long x, glp_long y)
|
alpar@9
|
107 { return
|
alpar@9
|
108 xladd(x, xlneg(y));
|
alpar@9
|
109 }
|
alpar@9
|
110
|
alpar@9
|
111 /***********************************************************************
|
alpar@9
|
112 * NAME
|
alpar@9
|
113 *
|
alpar@9
|
114 * xlcmp - compare long integers
|
alpar@9
|
115 *
|
alpar@9
|
116 * SYNOPSIS
|
alpar@9
|
117 *
|
alpar@9
|
118 * #include "glplib.h"
|
alpar@9
|
119 * int xlcmp(glp_long x, glp_long y);
|
alpar@9
|
120 *
|
alpar@9
|
121 * RETURNS
|
alpar@9
|
122 *
|
alpar@9
|
123 * The routine xlcmp returns the sign of the difference x - y. */
|
alpar@9
|
124
|
alpar@9
|
125 int xlcmp(glp_long x, glp_long y)
|
alpar@9
|
126 { if (x.hi >= 0 && y.hi < 0) return +1;
|
alpar@9
|
127 if (x.hi < 0 && y.hi >= 0) return -1;
|
alpar@9
|
128 if ((unsigned int)x.hi < (unsigned int)y.hi) return -1;
|
alpar@9
|
129 if ((unsigned int)x.hi > (unsigned int)y.hi) return +1;
|
alpar@9
|
130 if ((unsigned int)x.lo < (unsigned int)y.lo) return -1;
|
alpar@9
|
131 if ((unsigned int)x.lo > (unsigned int)y.lo) return +1;
|
alpar@9
|
132 return 0;
|
alpar@9
|
133 }
|
alpar@9
|
134
|
alpar@9
|
135 /***********************************************************************
|
alpar@9
|
136 * NAME
|
alpar@9
|
137 *
|
alpar@9
|
138 * xlmul - multiply long integers
|
alpar@9
|
139 *
|
alpar@9
|
140 * SYNOPSIS
|
alpar@9
|
141 *
|
alpar@9
|
142 * #include "glplib.h"
|
alpar@9
|
143 * glp_long xlmul(glp_long x, glp_long y);
|
alpar@9
|
144 *
|
alpar@9
|
145 * RETURNS
|
alpar@9
|
146 *
|
alpar@9
|
147 * The routine xlmul returns the product x * y. */
|
alpar@9
|
148
|
alpar@9
|
149 glp_long xlmul(glp_long x, glp_long y)
|
alpar@9
|
150 { unsigned short xx[8], yy[4];
|
alpar@9
|
151 xx[4] = (unsigned short)x.lo;
|
alpar@9
|
152 xx[5] = (unsigned short)(x.lo >> 16);
|
alpar@9
|
153 xx[6] = (unsigned short)x.hi;
|
alpar@9
|
154 xx[7] = (unsigned short)(x.hi >> 16);
|
alpar@9
|
155 yy[0] = (unsigned short)y.lo;
|
alpar@9
|
156 yy[1] = (unsigned short)(y.lo >> 16);
|
alpar@9
|
157 yy[2] = (unsigned short)y.hi;
|
alpar@9
|
158 yy[3] = (unsigned short)(y.hi >> 16);
|
alpar@9
|
159 bigmul(4, 4, xx, yy);
|
alpar@9
|
160 x.lo = (unsigned int)xx[0] | ((unsigned int)xx[1] << 16);
|
alpar@9
|
161 x.hi = (unsigned int)xx[2] | ((unsigned int)xx[3] << 16);
|
alpar@9
|
162 return x;
|
alpar@9
|
163 }
|
alpar@9
|
164
|
alpar@9
|
165 /***********************************************************************
|
alpar@9
|
166 * NAME
|
alpar@9
|
167 *
|
alpar@9
|
168 * xldiv - divide long integers
|
alpar@9
|
169 *
|
alpar@9
|
170 * SYNOPSIS
|
alpar@9
|
171 *
|
alpar@9
|
172 * #include "glplib.h"
|
alpar@9
|
173 * glp_ldiv xldiv(glp_long x, glp_long y);
|
alpar@9
|
174 *
|
alpar@9
|
175 * RETURNS
|
alpar@9
|
176 *
|
alpar@9
|
177 * The routine xldiv returns a structure of type glp_ldiv containing
|
alpar@9
|
178 * members quot (the quotient) and rem (the remainder), both of type
|
alpar@9
|
179 * glp_long. */
|
alpar@9
|
180
|
alpar@9
|
181 glp_ldiv xldiv(glp_long x, glp_long y)
|
alpar@9
|
182 { glp_ldiv t;
|
alpar@9
|
183 int m, sx, sy;
|
alpar@9
|
184 unsigned short xx[8], yy[4];
|
alpar@9
|
185 /* sx := sign(x) */
|
alpar@9
|
186 sx = (x.hi < 0);
|
alpar@9
|
187 /* sy := sign(y) */
|
alpar@9
|
188 sy = (y.hi < 0);
|
alpar@9
|
189 /* x := |x| */
|
alpar@9
|
190 if (sx) x = xlneg(x);
|
alpar@9
|
191 /* y := |y| */
|
alpar@9
|
192 if (sy) y = xlneg(y);
|
alpar@9
|
193 /* compute x div y and x mod y */
|
alpar@9
|
194 xx[0] = (unsigned short)x.lo;
|
alpar@9
|
195 xx[1] = (unsigned short)(x.lo >> 16);
|
alpar@9
|
196 xx[2] = (unsigned short)x.hi;
|
alpar@9
|
197 xx[3] = (unsigned short)(x.hi >> 16);
|
alpar@9
|
198 yy[0] = (unsigned short)y.lo;
|
alpar@9
|
199 yy[1] = (unsigned short)(y.lo >> 16);
|
alpar@9
|
200 yy[2] = (unsigned short)y.hi;
|
alpar@9
|
201 yy[3] = (unsigned short)(y.hi >> 16);
|
alpar@9
|
202 if (yy[3])
|
alpar@9
|
203 m = 4;
|
alpar@9
|
204 else if (yy[2])
|
alpar@9
|
205 m = 3;
|
alpar@9
|
206 else if (yy[1])
|
alpar@9
|
207 m = 2;
|
alpar@9
|
208 else if (yy[0])
|
alpar@9
|
209 m = 1;
|
alpar@9
|
210 else
|
alpar@9
|
211 xerror("xldiv: divide by zero\n");
|
alpar@9
|
212 bigdiv(4 - m, m, xx, yy);
|
alpar@9
|
213 /* remainder in x[0], x[1], ..., x[m-1] */
|
alpar@9
|
214 t.rem.lo = (unsigned int)xx[0], t.rem.hi = 0;
|
alpar@9
|
215 if (m >= 2) t.rem.lo |= (unsigned int)xx[1] << 16;
|
alpar@9
|
216 if (m >= 3) t.rem.hi = (unsigned int)xx[2];
|
alpar@9
|
217 if (m >= 4) t.rem.hi |= (unsigned int)xx[3] << 16;
|
alpar@9
|
218 if (sx) t.rem = xlneg(t.rem);
|
alpar@9
|
219 /* quotient in x[m], x[m+1], ..., x[4] */
|
alpar@9
|
220 t.quot.lo = (unsigned int)xx[m], t.quot.hi = 0;
|
alpar@9
|
221 if (m <= 3) t.quot.lo |= (unsigned int)xx[m+1] << 16;
|
alpar@9
|
222 if (m <= 2) t.quot.hi = (unsigned int)xx[m+2];
|
alpar@9
|
223 if (m <= 1) t.quot.hi |= (unsigned int)xx[m+3] << 16;
|
alpar@9
|
224 if (sx ^ sy) t.quot = xlneg(t.quot);
|
alpar@9
|
225 return t;
|
alpar@9
|
226 }
|
alpar@9
|
227
|
alpar@9
|
228 /***********************************************************************
|
alpar@9
|
229 * NAME
|
alpar@9
|
230 *
|
alpar@9
|
231 * xltod - convert long integer to double
|
alpar@9
|
232 *
|
alpar@9
|
233 * SYNOPSIS
|
alpar@9
|
234 *
|
alpar@9
|
235 * #include "glplib.h"
|
alpar@9
|
236 * double xltod(glp_long x);
|
alpar@9
|
237 *
|
alpar@9
|
238 * RETURNS
|
alpar@9
|
239 *
|
alpar@9
|
240 * The routine xltod returns x converted to double. */
|
alpar@9
|
241
|
alpar@9
|
242 double xltod(glp_long x)
|
alpar@9
|
243 { double s, z;
|
alpar@9
|
244 if (x.hi >= 0)
|
alpar@9
|
245 s = +1.0;
|
alpar@9
|
246 else
|
alpar@9
|
247 s = -1.0, x = xlneg(x);
|
alpar@9
|
248 if (x.hi >= 0)
|
alpar@9
|
249 z = 4294967296.0 * (double)x.hi + (double)(unsigned int)x.lo;
|
alpar@9
|
250 else
|
alpar@9
|
251 { xassert(x.hi == 0x80000000 && x.lo == 0x00000000);
|
alpar@9
|
252 z = 9223372036854775808.0; /* 2^63 */
|
alpar@9
|
253 }
|
alpar@9
|
254 return s * z;
|
alpar@9
|
255 }
|
alpar@9
|
256
|
alpar@9
|
257 char *xltoa(glp_long x, char *s)
|
alpar@9
|
258 { /* convert long integer to character string */
|
alpar@9
|
259 static const char *d = "0123456789";
|
alpar@9
|
260 glp_ldiv t;
|
alpar@9
|
261 int neg, len;
|
alpar@9
|
262 if (x.hi >= 0)
|
alpar@9
|
263 neg = 0;
|
alpar@9
|
264 else
|
alpar@9
|
265 neg = 1, x = xlneg(x);
|
alpar@9
|
266 if (x.hi >= 0)
|
alpar@9
|
267 { len = 0;
|
alpar@9
|
268 while (!(x.hi == 0 && x.lo == 0))
|
alpar@9
|
269 { t = xldiv(x, xlset(10));
|
alpar@9
|
270 xassert(0 <= t.rem.lo && t.rem.lo <= 9);
|
alpar@9
|
271 s[len++] = d[t.rem.lo];
|
alpar@9
|
272 x = t.quot;
|
alpar@9
|
273 }
|
alpar@9
|
274 if (len == 0) s[len++] = d[0];
|
alpar@9
|
275 if (neg) s[len++] = '-';
|
alpar@9
|
276 s[len] = '\0';
|
alpar@9
|
277 strrev(s);
|
alpar@9
|
278 }
|
alpar@9
|
279 else
|
alpar@9
|
280 strcpy(s, "-9223372036854775808"); /* -2^63 */
|
alpar@9
|
281 return s;
|
alpar@9
|
282 }
|
alpar@9
|
283
|
alpar@9
|
284 /**********************************************************************/
|
alpar@9
|
285
|
alpar@9
|
286 #if 0
|
alpar@9
|
287 #include "glprng.h"
|
alpar@9
|
288
|
alpar@9
|
289 #define N_TEST 1000000
|
alpar@9
|
290 /* number of tests */
|
alpar@9
|
291
|
alpar@9
|
292 static glp_long myrand(RNG *rand)
|
alpar@9
|
293 { glp_long x;
|
alpar@9
|
294 int k;
|
alpar@9
|
295 k = rng_unif_rand(rand, 4);
|
alpar@9
|
296 xassert(0 <= k && k <= 3);
|
alpar@9
|
297 x.lo = rng_unif_rand(rand, 65536);
|
alpar@9
|
298 if (k == 1 || k == 3)
|
alpar@9
|
299 { x.lo <<= 16;
|
alpar@9
|
300 x.lo += rng_unif_rand(rand, 65536);
|
alpar@9
|
301 }
|
alpar@9
|
302 if (k <= 1)
|
alpar@9
|
303 x.hi = 0;
|
alpar@9
|
304 else
|
alpar@9
|
305 x.hi = rng_unif_rand(rand, 65536);
|
alpar@9
|
306 if (k == 3)
|
alpar@9
|
307 { x.hi <<= 16;
|
alpar@9
|
308 x.hi += rng_unif_rand(rand, 65536);
|
alpar@9
|
309 }
|
alpar@9
|
310 if (rng_unif_rand(rand, 2)) x = xlneg(x);
|
alpar@9
|
311 return x;
|
alpar@9
|
312 }
|
alpar@9
|
313
|
alpar@9
|
314 int main(void)
|
alpar@9
|
315 { RNG *rand;
|
alpar@9
|
316 glp_long x, y;
|
alpar@9
|
317 glp_ldiv z;
|
alpar@9
|
318 int test;
|
alpar@9
|
319 rand = rng_create_rand();
|
alpar@9
|
320 for (test = 1; test <= N_TEST; test++)
|
alpar@9
|
321 { x = myrand(rand);
|
alpar@9
|
322 y = myrand(rand);
|
alpar@9
|
323 if (y.lo == 0 && y.hi == 0) y.lo = 1;
|
alpar@9
|
324 /* z.quot := x div y, z.rem := x mod y */
|
alpar@9
|
325 z = xldiv(x, y);
|
alpar@9
|
326 /* x must be equal to y * z.quot + z.rem */
|
alpar@9
|
327 xassert(xlcmp(x, xladd(xlmul(y, z.quot), z.rem)) == 0);
|
alpar@9
|
328 }
|
alpar@9
|
329 xprintf("%d tests successfully passed\n", N_TEST);
|
alpar@9
|
330 rng_delete_rand(rand);
|
alpar@9
|
331 return 0;
|
alpar@9
|
332 }
|
alpar@9
|
333 #endif
|
alpar@9
|
334
|
alpar@9
|
335 /* eof */
|