⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 glplib05.c

📁 著名的大规模线性规划求解器源码GLPK.C语言版本,可以修剪.内有详细帮助文档.
💻 C
字号:
/* glplib05.c (bignum arithmetic) *//************************************************************************  This code is part of GLPK (GNU Linear Programming Kit).**  Copyright (C) 2000,01,02,03,04,05,06,07,08,2009 Andrew Makhorin,*  Department for Applied Informatics, Moscow Aviation Institute,*  Moscow, Russia. All rights reserved. E-mail: <mao@mai2.rcnet.ru>.**  GLPK is free software: you can redistribute it and/or modify it*  under the terms of the GNU General Public License as published by*  the Free Software Foundation, either version 3 of the License, or*  (at your option) any later version.**  GLPK is distributed in the hope that it will be useful, but WITHOUT*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public*  License for more details.**  You should have received a copy of the GNU General Public License*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.***********************************************************************/#include "glplib.h"/************************************************************************  Two routines below are intended to multiply and divide unsigned*  integer numbers of arbitrary precision.* *  The routines assume that an unsigned integer number is represented in*  the positional numeral system with the base 2^16 = 65536, i.e. each*  "digit" of the number is in the range [0, 65535] and represented as*  a 16-bit value of the unsigned short type. In other words, a number x*  has the following representation:* *         n-1*     x = sum d[j] * 65536^j,*         j=0* *  where n is the number of places (positions), and d[j] is j-th "digit"*  of x, 0 <= d[j] <= 65535.***********************************************************************//************************************************************************  NAME**  bigmul - multiply unsigned integer numbers of arbitrary precision* *  SYNOPSIS* *  #include "glplib.h"*  void bigmul(int n, int m, unsigned short x[], unsigned short y[]);* *  DESCRIPTION* *  The routine bigmul multiplies unsigned integer numbers of arbitrary*  precision.* *  n is the number of digits of multiplicand, n >= 1;* *  m is the number of digits of multiplier, m >= 1;* *  x is an array containing digits of the multiplicand in elements*  x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are*  ignored on entry.* *  y is an array containing digits of the multiplier in elements y[0],*  y[1], ..., y[m-1].* *  On exit digits of the product are stored in elements x[0], x[1], ...,*  x[n+m-1]. The array y is not changed. */void bigmul(int n, int m, unsigned short x[], unsigned short y[]){     int i, j;      unsigned int t;      xassert(n >= 1);      xassert(m >= 1);      for (j = 0; j < m; j++) x[j] = 0;      for (i = 0; i < n; i++)      {  if (x[i+m])         {  t = 0;            for (j = 0; j < m; j++)            {  t += (unsigned int)x[i+m] * (unsigned int)y[j] +                    (unsigned int)x[i+j];               x[i+j] = (unsigned short)t;               t >>= 16;            }            x[i+m] = (unsigned short)t;         }      }      return;}/************************************************************************  NAME**  bigdiv - divide unsigned integer numbers of arbitrary precision* *  SYNOPSIS* *  #include "glplib.h"*  void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);* *  DESCRIPTION* *  The routine bigdiv divides one unsigned integer number of arbitrary*  precision by another with the algorithm described in [1].* *  n is the difference between the number of digits of dividend and the*  number of digits of divisor, n >= 0.* *  m is the number of digits of divisor, m >= 1.* *  x is an array containing digits of the dividend in elements x[0],*  x[1], ..., x[n+m-1].* *  y is an array containing digits of the divisor in elements y[0],*  y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero.* *  On exit n+1 digits of the quotient are stored in elements x[m],*  x[m+1], ..., x[n+m], and m digits of the remainder are stored in*  elements x[0], x[1], ..., x[m-1]. The array y is changed but then*  restored.**  REFERENCES**  1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical*  Algorithms. Stanford University, 1969. */void bigdiv(int n, int m, unsigned short x[], unsigned short y[]){     int i, j;      unsigned int t;      unsigned short d, q, r;      xassert(n >= 0);      xassert(m >= 1);      xassert(y[m-1] != 0);      /* special case when divisor has the only digit */      if (m == 1)      {  d = 0;         for (i = n; i >= 0; i--)         {  t = ((unsigned int)d << 16) + (unsigned int)x[i];            x[i+1] = (unsigned short)(t / y[0]);            d = (unsigned short)(t % y[0]);         }         x[0] = d;         goto done;      }      /* multiply dividend and divisor by a normalizing coefficient in         order to provide the condition y[m-1] >= base / 2 */      d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1));      if (d == 1)         x[n+m] = 0;      else      {  t = 0;         for (i = 0; i < n+m; i++)         {  t += (unsigned int)x[i] * (unsigned int)d;            x[i] = (unsigned short)t;            t >>= 16;         }         x[n+m] = (unsigned short)t;         t = 0;         for (j = 0; j < m; j++)         {  t += (unsigned int)y[j] * (unsigned int)d;            y[j] = (unsigned short)t;            t >>= 16;         }      }      /* main loop */      for (i = n; i >= 0; i--)      {  /* estimate and correct the current digit of quotient */         if (x[i+m] < y[m-1])         {  t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1];            q = (unsigned short)(t / (unsigned int)y[m-1]);            r = (unsigned short)(t % (unsigned int)y[m-1]);            if (q == 0) goto putq; else goto test;         }         q = 0;         r = x[i+m-1];decr:    q--; /* if q = 0 then q-- = 0xFFFF */         t = (unsigned int)r + (unsigned int)y[m-1];         r = (unsigned short)t;         if (t > 0xFFFF) goto msub;test:    t = (unsigned int)y[m-2] * (unsigned int)q;         if ((unsigned short)(t >> 16) > r) goto decr;         if ((unsigned short)(t >> 16) < r) goto msub;         if ((unsigned short)t > x[i+m-2]) goto decr;msub:    /* now subtract divisor multiplied by the current digit of            quotient from the current dividend */         if (q == 0) goto putq;         t = 0;         for (j = 0; j < m; j++)         {  t += (unsigned int)y[j] * (unsigned int)q;            if (x[i+j] < (unsigned short)t) t += 0x10000;            x[i+j] -= (unsigned short)t;            t >>= 16;         }         if (x[i+m] >= (unsigned short)t) goto putq;         /* perform correcting addition, because the current digit of            quotient is greater by one than its correct value */         q--;         t = 0;         for (j = 0; j < m; j++)         {  t += (unsigned int)x[i+j] + (unsigned int)y[j];            x[i+j] = (unsigned short)t;            t >>= 16;         }putq:    /* store the current digit of quotient */         x[i+m] = q;      }      /* divide divisor and remainder by the normalizing coefficient in         order to restore their original values */      if (d > 1)      {  t = 0;         for (i = m-1; i >= 0; i--)         {  t = (t << 16) + (unsigned int)x[i];            x[i] = (unsigned short)(t / (unsigned int)d);            t %= (unsigned int)d;         }         t = 0;         for (j = m-1; j >= 0; j--)         {  t = (t << 16) + (unsigned int)y[j];            y[j] = (unsigned short)(t / (unsigned int)d);            t %= (unsigned int)d;         }      }done: return;}/**********************************************************************/#if 0#include <assert.h>#include <stdio.h>#include <stdlib.h>#include "glprng.h"#define N_MAX 7/* maximal number of digits in multiplicand */#define M_MAX 5/* maximal number of digits in multiplier */#define N_TEST 1000000/* number of tests */int main(void){     RNG *rand;      int d, j, n, m, test;      unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX];      rand = rng_create_rand();      for (test = 1; test <= N_TEST; test++)      {  /* x[0,...,n-1] := multiplicand */         n = 1 + rng_unif_rand(rand, N_MAX-1);         assert(1 <= n && n <= N_MAX);         for (j = 0; j < n; j++)         {  d = rng_unif_rand(rand, 65536);            assert(0 <= d && d <= 65535);            x[j] = (unsigned short)d;         }         /* y[0,...,m-1] := multiplier */         m = 1 + rng_unif_rand(rand, M_MAX-1);         assert(1 <= m && m <= M_MAX);         for (j = 0; j < m; j++)         {  d = rng_unif_rand(rand, 65536);            assert(0 <= d && d <= 65535);            y[j] = (unsigned short)d;         }         if (y[m-1] == 0) y[m-1] = 1;         /* z[0,...,n+m-1] := x * y */         for (j = 0; j < n; j++) z[m+j] = x[j];         bigmul(n, m, z, y);         /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */         bigdiv(n, m, z, y);         /* z mod y must be 0 */         for (j = 0; j < m; j++) assert(z[j] == 0);         /* z div y must be x */         for (j = 0; j < n; j++) assert(z[m+j] == x[j]);      }      fprintf(stderr, "%d tests successfully passed\n", N_TEST);      rng_delete_rand(rand);      return 0;}#endif/* eof */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -