alpar@9: /* glplib02.c (64-bit arithmetic) */ alpar@9: alpar@9: /*********************************************************************** alpar@9: * This code is part of GLPK (GNU Linear Programming Kit). alpar@9: * alpar@9: * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, alpar@9: * 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics, alpar@9: * Moscow Aviation Institute, Moscow, Russia. All rights reserved. alpar@9: * E-mail: . alpar@9: * alpar@9: * GLPK is free software: you can redistribute it and/or modify it alpar@9: * under the terms of the GNU General Public License as published by alpar@9: * the Free Software Foundation, either version 3 of the License, or alpar@9: * (at your option) any later version. alpar@9: * alpar@9: * GLPK is distributed in the hope that it will be useful, but WITHOUT alpar@9: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY alpar@9: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public alpar@9: * License for more details. alpar@9: * alpar@9: * You should have received a copy of the GNU General Public License alpar@9: * along with GLPK. If not, see . alpar@9: ***********************************************************************/ alpar@9: alpar@9: #include "glpenv.h" alpar@9: #include "glplib.h" alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * xlset - expand integer to long integer alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * #include "glplib.h" alpar@9: * glp_long xlset(int x); alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * The routine xlset returns x expanded to long integer. */ alpar@9: alpar@9: glp_long xlset(int x) alpar@9: { glp_long t; alpar@9: t.lo = x, t.hi = (x >= 0 ? 0 : -1); alpar@9: return t; alpar@9: } alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * xlneg - negate long integer alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * #include "glplib.h" alpar@9: * glp_long xlneg(glp_long x); alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * The routine xlneg returns the difference 0 - x. */ alpar@9: alpar@9: glp_long xlneg(glp_long x) alpar@9: { if (x.lo) alpar@9: x.lo = - x.lo, x.hi = ~x.hi; alpar@9: else alpar@9: x.hi = - x.hi; alpar@9: return x; alpar@9: } alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * xladd - add long integers alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * #include "glplib.h" alpar@9: * glp_long xladd(glp_long x, glp_long y); alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * The routine xladd returns the sum x + y. */ alpar@9: alpar@9: glp_long xladd(glp_long x, glp_long y) alpar@9: { if ((unsigned int)x.lo <= 0xFFFFFFFF - (unsigned int)y.lo) alpar@9: x.lo += y.lo, x.hi += y.hi; alpar@9: else alpar@9: x.lo += y.lo, x.hi += y.hi + 1; alpar@9: return x; alpar@9: } alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * xlsub - subtract long integers alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * #include "glplib.h" alpar@9: * glp_long xlsub(glp_long x, glp_long y); alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * The routine xlsub returns the difference x - y. */ alpar@9: alpar@9: glp_long xlsub(glp_long x, glp_long y) alpar@9: { return alpar@9: xladd(x, xlneg(y)); alpar@9: } alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * xlcmp - compare long integers alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * #include "glplib.h" alpar@9: * int xlcmp(glp_long x, glp_long y); alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * The routine xlcmp returns the sign of the difference x - y. */ alpar@9: alpar@9: int xlcmp(glp_long x, glp_long y) alpar@9: { if (x.hi >= 0 && y.hi < 0) return +1; alpar@9: if (x.hi < 0 && y.hi >= 0) return -1; alpar@9: if ((unsigned int)x.hi < (unsigned int)y.hi) return -1; alpar@9: if ((unsigned int)x.hi > (unsigned int)y.hi) return +1; alpar@9: if ((unsigned int)x.lo < (unsigned int)y.lo) return -1; alpar@9: if ((unsigned int)x.lo > (unsigned int)y.lo) return +1; alpar@9: return 0; alpar@9: } alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * xlmul - multiply long integers alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * #include "glplib.h" alpar@9: * glp_long xlmul(glp_long x, glp_long y); alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * The routine xlmul returns the product x * y. */ alpar@9: alpar@9: glp_long xlmul(glp_long x, glp_long y) alpar@9: { unsigned short xx[8], yy[4]; alpar@9: xx[4] = (unsigned short)x.lo; alpar@9: xx[5] = (unsigned short)(x.lo >> 16); alpar@9: xx[6] = (unsigned short)x.hi; alpar@9: xx[7] = (unsigned short)(x.hi >> 16); alpar@9: yy[0] = (unsigned short)y.lo; alpar@9: yy[1] = (unsigned short)(y.lo >> 16); alpar@9: yy[2] = (unsigned short)y.hi; alpar@9: yy[3] = (unsigned short)(y.hi >> 16); alpar@9: bigmul(4, 4, xx, yy); alpar@9: x.lo = (unsigned int)xx[0] | ((unsigned int)xx[1] << 16); alpar@9: x.hi = (unsigned int)xx[2] | ((unsigned int)xx[3] << 16); alpar@9: return x; alpar@9: } alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * xldiv - divide long integers alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * #include "glplib.h" alpar@9: * glp_ldiv xldiv(glp_long x, glp_long y); alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * The routine xldiv returns a structure of type glp_ldiv containing alpar@9: * members quot (the quotient) and rem (the remainder), both of type alpar@9: * glp_long. */ alpar@9: alpar@9: glp_ldiv xldiv(glp_long x, glp_long y) alpar@9: { glp_ldiv t; alpar@9: int m, sx, sy; alpar@9: unsigned short xx[8], yy[4]; alpar@9: /* sx := sign(x) */ alpar@9: sx = (x.hi < 0); alpar@9: /* sy := sign(y) */ alpar@9: sy = (y.hi < 0); alpar@9: /* x := |x| */ alpar@9: if (sx) x = xlneg(x); alpar@9: /* y := |y| */ alpar@9: if (sy) y = xlneg(y); alpar@9: /* compute x div y and x mod y */ alpar@9: xx[0] = (unsigned short)x.lo; alpar@9: xx[1] = (unsigned short)(x.lo >> 16); alpar@9: xx[2] = (unsigned short)x.hi; alpar@9: xx[3] = (unsigned short)(x.hi >> 16); alpar@9: yy[0] = (unsigned short)y.lo; alpar@9: yy[1] = (unsigned short)(y.lo >> 16); alpar@9: yy[2] = (unsigned short)y.hi; alpar@9: yy[3] = (unsigned short)(y.hi >> 16); alpar@9: if (yy[3]) alpar@9: m = 4; alpar@9: else if (yy[2]) alpar@9: m = 3; alpar@9: else if (yy[1]) alpar@9: m = 2; alpar@9: else if (yy[0]) alpar@9: m = 1; alpar@9: else alpar@9: xerror("xldiv: divide by zero\n"); alpar@9: bigdiv(4 - m, m, xx, yy); alpar@9: /* remainder in x[0], x[1], ..., x[m-1] */ alpar@9: t.rem.lo = (unsigned int)xx[0], t.rem.hi = 0; alpar@9: if (m >= 2) t.rem.lo |= (unsigned int)xx[1] << 16; alpar@9: if (m >= 3) t.rem.hi = (unsigned int)xx[2]; alpar@9: if (m >= 4) t.rem.hi |= (unsigned int)xx[3] << 16; alpar@9: if (sx) t.rem = xlneg(t.rem); alpar@9: /* quotient in x[m], x[m+1], ..., x[4] */ alpar@9: t.quot.lo = (unsigned int)xx[m], t.quot.hi = 0; alpar@9: if (m <= 3) t.quot.lo |= (unsigned int)xx[m+1] << 16; alpar@9: if (m <= 2) t.quot.hi = (unsigned int)xx[m+2]; alpar@9: if (m <= 1) t.quot.hi |= (unsigned int)xx[m+3] << 16; alpar@9: if (sx ^ sy) t.quot = xlneg(t.quot); alpar@9: return t; alpar@9: } alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * xltod - convert long integer to double alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * #include "glplib.h" alpar@9: * double xltod(glp_long x); alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * The routine xltod returns x converted to double. */ alpar@9: alpar@9: double xltod(glp_long x) alpar@9: { double s, z; alpar@9: if (x.hi >= 0) alpar@9: s = +1.0; alpar@9: else alpar@9: s = -1.0, x = xlneg(x); alpar@9: if (x.hi >= 0) alpar@9: z = 4294967296.0 * (double)x.hi + (double)(unsigned int)x.lo; alpar@9: else alpar@9: { xassert(x.hi == 0x80000000 && x.lo == 0x00000000); alpar@9: z = 9223372036854775808.0; /* 2^63 */ alpar@9: } alpar@9: return s * z; alpar@9: } alpar@9: alpar@9: char *xltoa(glp_long x, char *s) alpar@9: { /* convert long integer to character string */ alpar@9: static const char *d = "0123456789"; alpar@9: glp_ldiv t; alpar@9: int neg, len; alpar@9: if (x.hi >= 0) alpar@9: neg = 0; alpar@9: else alpar@9: neg = 1, x = xlneg(x); alpar@9: if (x.hi >= 0) alpar@9: { len = 0; alpar@9: while (!(x.hi == 0 && x.lo == 0)) alpar@9: { t = xldiv(x, xlset(10)); alpar@9: xassert(0 <= t.rem.lo && t.rem.lo <= 9); alpar@9: s[len++] = d[t.rem.lo]; alpar@9: x = t.quot; alpar@9: } alpar@9: if (len == 0) s[len++] = d[0]; alpar@9: if (neg) s[len++] = '-'; alpar@9: s[len] = '\0'; alpar@9: strrev(s); alpar@9: } alpar@9: else alpar@9: strcpy(s, "-9223372036854775808"); /* -2^63 */ alpar@9: return s; alpar@9: } alpar@9: alpar@9: /**********************************************************************/ alpar@9: alpar@9: #if 0 alpar@9: #include "glprng.h" alpar@9: alpar@9: #define N_TEST 1000000 alpar@9: /* number of tests */ alpar@9: alpar@9: static glp_long myrand(RNG *rand) alpar@9: { glp_long x; alpar@9: int k; alpar@9: k = rng_unif_rand(rand, 4); alpar@9: xassert(0 <= k && k <= 3); alpar@9: x.lo = rng_unif_rand(rand, 65536); alpar@9: if (k == 1 || k == 3) alpar@9: { x.lo <<= 16; alpar@9: x.lo += rng_unif_rand(rand, 65536); alpar@9: } alpar@9: if (k <= 1) alpar@9: x.hi = 0; alpar@9: else alpar@9: x.hi = rng_unif_rand(rand, 65536); alpar@9: if (k == 3) alpar@9: { x.hi <<= 16; alpar@9: x.hi += rng_unif_rand(rand, 65536); alpar@9: } alpar@9: if (rng_unif_rand(rand, 2)) x = xlneg(x); alpar@9: return x; alpar@9: } alpar@9: alpar@9: int main(void) alpar@9: { RNG *rand; alpar@9: glp_long x, y; alpar@9: glp_ldiv z; alpar@9: int test; alpar@9: rand = rng_create_rand(); alpar@9: for (test = 1; test <= N_TEST; test++) alpar@9: { x = myrand(rand); alpar@9: y = myrand(rand); alpar@9: if (y.lo == 0 && y.hi == 0) y.lo = 1; alpar@9: /* z.quot := x div y, z.rem := x mod y */ alpar@9: z = xldiv(x, y); alpar@9: /* x must be equal to y * z.quot + z.rem */ alpar@9: xassert(xlcmp(x, xladd(xlmul(y, z.quot), z.rem)) == 0); alpar@9: } alpar@9: xprintf("%d tests successfully passed\n", N_TEST); alpar@9: rng_delete_rand(rand); alpar@9: return 0; alpar@9: } alpar@9: #endif alpar@9: alpar@9: /* eof */