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