bignum.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,299 行 · 第 1/4 页

C
1,299
字号
//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
//
// Created: MBN 11/01/89 -- Initial implementation
// Updated: CLJ 04/19/90 -- Finished initial implementation of all functions
// Updated: MJF 05/24/90 -- Added group names to RAISE
// Updated: MJF 07/31/90 -- Added terse print
// Updated: DAN 01/08/91 -- Fixed bug in add and multiply_aux
// Updated: MJF 01/17/91 -- Fixed delete operations
// Updated: MJF 01/21/91 -- Fixed multiply_aux, divide_aux and left_shift
// Updated: DLS 03/22/91 -- New lite version
// Updated: JAM 08/12/92 -- removed DOS specifics, stdized #includes
// Updated: JAM 08/12/92 -- anach. form() replaced with iomanips
// Updated: JAM 08/12/92 -- added DBLRET_HACK in CoolBigNum(double)
// Updated: JAM 08/12/92 -- fixed(?) normalize() bug where 1 was being added
//                          to dividend Data which could cause it to wrap to 0
//
// The Bignum class implements  infinite precision integers  and arithmetic.  A
// Bignum  object storage  will grow and  shrink  in 16-bit chunks as necessary
// based upon  its current value.   Implicit  conversion to the  system defined
// types short, int, long,  float, and  double is supported by virtual operator
// member functions from   the  base Number   class.  Addition  and subtraction
// operations are performed by simple bitwise addition or subtraction on 32-bit
// boundaries with checks for carry flag propagation.   The  multiplication and
// division  operations  utilize  the algorithms   from  Knuth  Volume  2   for
// efficiency. However, the user is  warned that the  Bignum integer arithmetic
// class is still considerably slower than the built-in integer data types.
//

#ifndef BIGNUMH                                 // If no definition for class
#include <cool/Bignum.h>                        // include definition file
#endif

#include <string.h>             // Include standard strings
#define C_STRINGH

#include <math.h>               // Include the standard math library
#include <ctype.h>              // Include character macros
#include <stdlib.h>             // Include standard c library support
#include <limits.h>             // for CHAR_BIT

#include <iomanip.h>          // Include stream maniplutors (eg, hex, setw)

int CoolBignum_Init::count;                     
int    data_bits_s;                             // Initialize to 0 by default
long   radix_s;    

CoolBignum zero_s;                              // There is only 1 set of
CoolBignum one_s;                               // these Bignums
CoolBignum eight_s;                             
CoolBignum ten_s;                               // Constructors are called 
CoolBignum sixteen_s;                           // for static libraries.
CoolBignum max_short_s;
CoolBignum max_int_s;                           // No constructor called
CoolBignum max_long_s;                          // for dynamic libraries,
CoolBignum max_float_s;                         // so these bignums are blank
CoolBignum negmax_float_s;                              // so these bignums are blank
CoolBignum max_double_s;                        
CoolBignum negmax_double_s;

// Reinitialize one more time, if default constructor is called for 
// above globals.

CoolBignum_Init bignum_init2_s;         // Offset static/dynamic difference

CoolBignum_Init::CoolBignum_Init() {
  if ((count++ == 0) ||                         // from bignum_init1_s
      (((double)(max_double_s)) == 0.0)) {              // from bignum_init2_s
    data_bits_s   = BITS(Data);                 // This initializer creates
    radix_s       = long(pow(2.0,data_bits_s)); // correct values for
    zero_s       = CoolBignum();                // above global objects,
    one_s        = CoolBignum(long(1));         // as soon as Bignum.h is
    eight_s      = CoolBignum(long(8));         // included as header in
    ten_s        = CoolBignum(long(10));        // main.C
    sixteen_s    = CoolBignum(long(16));
    max_short_s  = CoolBignum(long(MAXSHORT));
    max_int_s    = CoolBignum(long(MAXINT));
    max_long_s   = CoolBignum(MAXLONG);
    max_float_s  = CoolBignum(MAXFLOAT);
    max_double_s = CoolBignum(MAXDOUBLE);
    negmax_float_s  = CoolBignum(-MAXFLOAT);
    negmax_double_s = CoolBignum(-MAXDOUBLE);
  }
}

CoolBignum_Init::~CoolBignum_Init() {}          // no clean up needed





// CoolBignum - simple constructor
// Inputs:  none
// Outputs:  initialized CoolBignum

CoolBignum::CoolBignum () {
  this->data = NULL;                            // No need to allocate yet
  this->count = 0;                              // Size of data is 0
  this->sign = 1;                               // CoolBignum >= 0
  this->state = N_OK;                           // State is ok
}



// ~CoolBignum - destructor
// Inputs:  none
// Outputs:  none

CoolBignum::~CoolBignum () {
  delete [] this->data;                 // Delete any allocated data
}



// CoolBignum - CoolBignum constructor with long argument
// Inputs:  long to be converted to CoolBignum
// Outputs:  new CoolBignum

CoolBignum::CoolBignum (const long inval) {
  long l = inval;
  if (l >= 0)                                   // Get correct sign
    this->sign = 1;
  else {
    l = -l;                                     // Get absolute value of l
    this->sign = -1;
  }
  Data buf[sizeof(l)];                  // Temp buffer to store l in
  Counter i = 0;                        // buffer index
  while (l) {                           // While more bits in l
    if (i >= sizeof(l)) {               // If no more buffer space
      this->state = N_NO_CONVERSION;    //   raise an exception
      no_conversion("CoolBignum(long)");
    }
    buf[i] = Data(l);                           // Peel off lower order bits
    l >>= data_bits_s;                          // Shift next bits into place
    i++;                                
  }
  this->data = ((this->count = i) > 0 ? // Allocate permanent data
    new Data[i] : 0);
  i = 0;                                       
  while (i < this->count) {                     // Save buffer into perm. data
    this->data[i] = buf[i];
    i++;
  }
  this->state = N_OK;                           // Set status to OK
}


// CoolBignum - CoolBignum constructor with double argument
// Inputs:  double to be converted to CoolBignum
// Outputs:  new CoolBignum

CoolBignum::CoolBignum (const double inval) {
  double d = inval;
  if (d >= 0)                                   // Get sign of d
    this->sign = 1;
  else {
    d = -d;                                     // Get absolute value of d
    this->sign = -1;
  }
#if 1
  // need to assign 'double' return value to temporary because of small error
  const double LOG10_MAXDOUBLE = log10(MAXDOUBLE);
  const double LOG10_RADIX_S = log10(double(radix_s));
  const int buf_size_s = int(LOG10_MAXDOUBLE/LOG10_RADIX_S);
  if (buf_size_s==63 && d==MAXDOUBLE) {
    printf("buf_size_s is 63 for MAXDOUBLE!\n");
    cout << setprecision(16) << MAXDOUBLE << ' ' << radix_s << ' ' << LOG10_MAXDOUBLE << ' ' << LOG10_RADIX_S << ' ' << buf_size_s << endl;
    abort();
    }
#else  // 
  static int buf_size_s = 
    int (log10(MAXDOUBLE)/log10(radix_s));      // Size of buffer to convert d
#endif
  Data *buf = new Data[buf_size_s];             // Buffer to convert d into
  Counter i = 0;                                // buffer index
    while (d >= 1.0) {                          
    if (i >= buf_size_s) {                      // If no more buffer space
      this->state = N_NO_CONVERSION;            //   raise an exception
      no_conversion("CoolBignum(double)");
    }
    buf[i] = Data(fmod(d,radix_s));             // Get next data "digit" from d
    d /= radix_s;                               // Shift d right 1 data "digit"
    i++;                                        // Increment buffer index
  }
  this->data = (i > 0 ? new Data[i] : 0);       // Allocate permanent data
  this->count = i;                              // Save count
  i = 0;                                       
  while (i < this->count) {                     // Copy temp buffer into 
    this->data[i] = buf[i];                     //   permanent data
    i++;
  }
  this->state = N_OK;                           // Set status to OK
  delete [] buf;                                // Deallocate buffer
}



// dtoBignum -- convert decimal string to CoolBignum
// Inputs:  string representation of decimal literal to be converted
// Outputs:  number of characters actually converted

int CoolBignum::dtoBignum (const char *s) {
  Counter len = 0;                              // No chars converted yet
  if (s[0] == '-' || s[0] == '+') len++;        // Skip over leading +,-
  while (isdigit(s[len])) {                     // If current char is digit
    (*this) = ((*this) * ten_s) +               // Shift CoolBignum left a decimal
      CoolBignum(long(s[len++] - '0'));         //   digit and add new digit
  }
  if (s[0] == '-') this->sign = -1;             // If s had leading -, note it
  return len;                                   // Return # of chars processed
}



// exptoBignum -- convert exponential string to a CoolBignum
// Inputs:  string representation of exponential literal to be converted
// Outputs:  none

void CoolBignum::exptoBignum (const char *s) {
  Counter pos = this->dtoBignum(s) + 1;         // Convert the base, skip [eE]
  long pow = atol(s + pos);                     // Convert the exponent to long
  while (pow-- > 0)                             // Raise CoolBignum to the given
    *this = (*this) * ten_s;                    //   power
}



// ctox - convert hex character to integer hex value (ASCII or EBCDIC)
// Inputs:  character representation of a hex number
// Outputs:  integer value of the hex number

unsigned int ctox (int c) {
  if ('0' <= c && c <= '9')
    return c - '0';
  if ('a' <= c && c <= 'f')
    return c - 'a' + 10;
  return c - 'A' + 10;
}



// xtoBignum -- convert hex string to CoolBignum value
// Inputs:  string representation of hex number to be converted
// Outputs:  none

void CoolBignum::xtoBignum (const char *s) {
  Counter size = strlen(s);
  Counter len = 2;                              // skip leading "0x"
  while (len < size) {                          // While there are more chars
    (*this) = ((*this) * sixteen_s) +           // Shift CoolBignum left one hex
      CoolBignum(long(ctox(s[len++])));         //   digit and add next digit
  }
}


  
// otoBignum -- convert octal string to CoolBignum
// Inputs:  string representation of octal number to be converted
// Outputs:  none

void CoolBignum::otoBignum (const char *s) {
  Counter size = strlen(s);
  Counter len = 0;                              // No chars converted yet
  while (len < size) {                          // While there are more chars
    (*this) = ((*this) * eight_s) +             // Shift CoolBignum left 1 oct dig.
      CoolBignum(long(s[len++] - '0'));         // Add next character value
  }
}



// CoolBignum -- CoolBignum constructor with string argument
// Inputs:  string representation of number to be converted to CoolBignum
// Outputs:  new CoolBignum with converted value

CoolBignum::CoolBignum (const char *s) {
  static CoolRegexp                                     // Declare CoolRegexp's for
    decimal(" *^[-+]?[1-9][0-9]*$"),                  // decimal
    exponential(" *^[-+]?[1-9][0-9]*[eE][1-9][0-9]*$"), // exponential
    hexadecimal(" *^[0][xX][0-9a-fA-F]+$"),           // hex
    octal(" *^[0][0-7]*$");                           // octal.

  // Init *this to a CoolBignum value of 0
  this->data = 0;                       
  this->count = 0;                              
  this->sign = 1;                               
  this->state = N_OK;

  if (decimal.find(s))                          // If string is decimal
    this->dtoBignum(s);                         // convert decimal to CoolBignum
  else if (exponential.find(s))                 // If string is exponential
    this->exptoBignum(s);                       // convert exp. to CoolBignum
  else if (hexadecimal.find(s))                 // If string is hex,
    this->xtoBignum(s);                         // convert hex to CoolBignum
  else if (octal.find(s))                       // If string is octal
    this->otoBignum(s);                         // convert octal to CoolBignum
  else {                                        // Otherwise
    this->state = N_NO_CONVERSION;              // raise an exception
    no_conversion("CoolBignum(const char *)");
  }
}



// CoolBignum - CoolBignum constructor with CoolBignum reference argument
// Inputs:  reference to CoolBignum
// Outputs:  new CoolBignum with same value as input

CoolBignum::CoolBignum (const CoolBignum& b) {
  this->count = b.count;                        // Copy b's count
  this->data =                                  // Allocate data if necessary
    (b.count > 0 ? new Data[b.count] : 0);
  for (Counter i = 0; i < this->count; i++)     // Copy b's data 
    this->data[i] = b.data[i];  
  this->sign = b.sign;                          // Copy b's sign

⌨️ 快捷键说明

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