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