bug-gmp
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

GMP C++ wrap


From: Hans Aberg
Subject: GMP C++ wrap
Date: Wed, 25 Apr 2001 13:56:31 +0200

At 08:13 +1000 2001/04/25, Kevin Ryde wrote:
>> I started on a C++ wrap, classes gmp::integer, gmp::rational, gmp::floating
>> that expand to the GMP C functions.
...
>Gerardo Ballabio has made good progress on such a wrapper,
>
>        http://www.sissa.it/~ballabio/gmp++.html

I had a look at this

My style is quite different; but my objectives are quite different.

I decided with only one header <gmp>, and the classes are put in a
namespace gmp.

Below is a sample, the integer class (with example code). The style is similar:
  gmp::integer x = ..., y = ..., z;
  z = x * y;
etc.

-- File <gmp> --------------------------------------------------------------

#include <iostream>
#include <string>

#include "gmp.h"
#include "gmp-impl.h"


namespace gmp {


typedef int relate;

const relate unrelated = -2;
const relate less = -1;
const relate equal = 0;
const relate greater = 1;

template<class A> // The sign of a number:
inline int sgn(A x) { return (x > 0) - (x < 0); }

inline bool less_equal(relate r) { return r == less || r == equal; }
inline bool greater_equal(relate r) { return r == greater || r == equal; }


class rational;
class floating;


class integer {
public:
  mpz_t value_;

public:
  integer() { mpz_init(value_); }
  ~integer() { mpz_clear(value_); }

  integer(const integer& x) { mpz_init_set(value_, x.value_); }
  integer& operator=(const integer& x) { mpz_set(value_, x.value_); return
*this; }

  integer(unsigned long int x) { mpz_init_set_ui(value_, x); }
  integer(signed long int x) { mpz_init_set_si(value_, x); }
  integer(double x) { mpz_init_set_d(value_, x); }
  integer(const char* str, int base = 0) { mpz_init_set_str(value_, str,
base); }
  // Make explicit functions, instaed of type conversions:
  // integer(const rational& x) { mpz_init_set_q(value_, x); }
  // integer(const floating& x) { mpz_init_set_f(value_, x); }

  integer& operator=(unsigned long int x) { mpz_set_ui(value_, x); return
*this; }
  integer& operator=(signed long int x) { mpz_set_si(value_, x); return
*this; }
  integer& operator=(double x) { mpz_set_d(value_, x); return *this; }
  integer& operator=(const char* str) { mpz_set_str(value_, str, 0); return
*this; }
  integer& operator=(const rational& x); // { mpz_set_q(value_, x); }
  integer& operator=(const floating& x); // { mpz_set_f(value_, x); }

  double get_d() const { return mpz_get_d(value_); }
  signed long int get_si() const { return mpz_get_si(value_); }
  unsigned long int get_ui() const { return mpz_get_ui(value_); }
  std::string str(int base = 10) const {
    char* cs = new char[mpz_sizeinbase(value_, base) + 2];
    mpz_get_str(cs, base, value_);
    std::string str_r(cs); delete[] cs;
    return str_r;
  }

  relate compare(const integer& x) const { return sgn(mpz_cmp(value_,
x.value_)); }

  void swap(integer& x) { mpz_swap(value_, x.value_); }

  size_t read(std::istream&, int base = 0);

  friend integer operator+(const integer&, const integer&);
  friend integer operator-(const integer&);
  friend integer operator-(const integer&, const integer&);
  friend integer operator*(const integer&, const integer&);

  friend bool operator<(const integer&, const integer&);
  friend bool operator<=(const integer&, const integer&);
  friend bool operator==(const integer&, const integer&);
  friend bool operator!=(const integer&, const integer&);
  friend bool operator>(const integer&, const integer&);
  friend bool operator>=(const integer&, const integer&);


  friend integer abs(const integer&); // Absolute value.

  friend std::istream& operator>>(std::istream&, integer&);
  friend std::ostream& operator<<(std::ostream&, const integer&);
};


inline integer operator+(const integer& x, const integer& y) {
  integer r;  mpz_add(r.value_, x.value_, y.value_);  return r;
}

inline integer operator-(const integer& x) {
  integer r;  mpz_neg(r.value_, x.value_);  return r;
}

inline integer operator-(const integer& x, const integer& y) {
  integer r;  mpz_sub(r.value_, x.value_, y.value_);  return r;
}

inline integer operator*(const integer& x, const integer& y) {
  integer r;  mpz_mul(r.value_, x.value_, y.value_);  return r;
}

inline bool operator<(const integer& x, const integer& y)
{  return x.compare(y) == less;  }

inline bool operator<=(const integer& x, const integer& y)
{  return less_equal(x.compare(y));  }

inline bool operator==(const integer& x, const integer& y)
{  return x.compare(y) == equal;  }

inline bool operator!=(const integer& x, const integer& y)
{  return x.compare(y) != equal;  }

inline bool operator>(const integer& x, const integer& y)
{  return x.compare(y) == greater;  }

inline bool operator>=(const integer& x, const integer& y)
{  return greater_equal(x.compare(y));  }


inline integer abs(const integer& x) {
  integer r;  mpz_abs(r.value_, x.value_);  return r;
}


inline std::istream& operator>>(std::istream& is, integer& x) {
  x.read(is);  return is;
}

inline std::ostream& operator<<(std::ostream& os, const integer& n) {
  return os << n.str();
}

} // namespace gmp

-- File <gmp.cc> --------------------------------------------------------------

#include <sstream>


namespace gmp {


  // Class integer:

static int digit_value_in_base(int c, int base) {
  int digit;

  if (isdigit(c))
    digit = c - '0';
  else if (islower(c))
    digit = c - 'a' + 10;
  else if (isupper(c))
    digit = c - 'A' + 10;
  else
    return -1;

  if (digit < base)
    return digit;
  return -1;
}


size_t integer::read(std::istream& stream, int base)
{
  mpz_ptr x = value_;
  char *str;
  size_t alloc_size, str_size;
  int c;
  int negative;
  mp_size_t xsize;
  size_t nread;

  nread = 0;

  /* Skip whitespace.  */
  do
    {
      c = stream.get();
      nread++;
    }
  while (isspace(c));

  negative = 0;
  if (c == '-')
    {
      negative = 1;
      c = stream.get();
      nread++;
    }

  if (digit_value_in_base (c, base == 0 ? 10 : base) < 0)
    return 0;     /* error if no digits */

  /* If BASE is 0, try to find out the base by looking at the initial
     characters.  */
  if (base == 0)
    {
      base = 10;
      if (c == '0')
  {
    base = 8;
    c = stream.get();
    nread++;
    if (c == 'x' || c == 'X')
      {
        base = 16;
        c = stream.get();
        nread++;
      }
    else if (c == 'b' || c == 'B')
      {
        base = 2;
        c = stream.get();
        nread++;
      }
  }
    }

  /* Skip leading zeros.  */
  while (c == '0')
    {
      c = stream.get();
      nread++;
    }

  alloc_size = 100;
  str = (char *) (*_mp_allocate_func) (alloc_size);
  str_size = 0;

  for (;;)
    {
      int dig;
      if (str_size >= alloc_size)
  {
    size_t old_alloc_size = alloc_size;
    alloc_size = alloc_size * 3 / 2;
    str = (char *) (*_mp_reallocate_func) (str, old_alloc_size, alloc_size);
  }
      dig = digit_value_in_base (c, base);
      if (dig < 0)
  break;
      str[str_size++] = dig;
      c = stream.get();
    }

  stream.unget();

  /* Make sure the string is not empty, mpn_set_str would fail.  */
  if (str_size == 0)
    {
      x->_mp_size = 0;
      (*_mp_free_func) (str, alloc_size);
      return nread;
    }

  xsize = (((mp_size_t) (str_size / __mp_bases[base].chars_per_bit_exactly))
     / BITS_PER_MP_LIMB + 2);
  if (x->_mp_alloc < xsize)
    _mpz_realloc (x, xsize);

  /* Convert the byte array in base BASE to our bignum format.  */
  xsize = mpn_set_str (x->_mp_d, (unsigned char *) str, str_size, base);
  x->_mp_size = negative ? -xsize : xsize;

  (*_mp_free_func) (str, alloc_size);
  return str_size + nread;
}

} // namespace gmp

--- File main.cc -----------------------------------------------------------

#include <iostream>

#include "gmp"

#define show_bool(x) (x? "true" : "false")

int main() {
  gmp::integer x, y;

  for (;;) {
    std::cout << "x = " << std::flush;
    if (!(std::cin >> x))  continue;
    if (x == -1L)  break;
    std::cout << "y = " << std::flush;
    if (!(std::cin >> y))  continue;

    std::cout << "    x = " << x << std::endl;
    std::cout << "    y = " << y << std::endl;

    std::cout << "   -x = " << -x << std::endl;
    std::cout << "x + y = " << x + y << std::endl;
    std::cout << "x - y = " << x - y << std::endl;
    std::cout << "x * y = " << x * y << std::endl;

    std::cout << " x < y = " << show_bool(x < y) << std::endl;
    std::cout << "x <= y = " << show_bool(x <= y) << std::endl;
    std::cout << "x == y = " << show_bool(x == y) << std::endl;
    std::cout << "x != y = " << show_bool(x != y) << std::endl;
    std::cout << " x > y = " << show_bool(x > y) << std::endl;
    std::cout << "x >= y = " << show_bool(x >= y) << std::endl;
  }

  std::cout << "Bye, bye!" << std::endl;

  return 0;
}

-----------------------------------------------------------------

  Hans Aberg





reply via email to

[Prev in Thread] Current Thread [Next in Thread]