cgal/Packages/Core/include/BigInt.inl

855 lines
19 KiB
C++

/******************************************************************
* Core Library, Version 1.5, August 2002
* Copyright (c) 1995-2002 Exact Computation Project
*
* File: BigInt.inl
* $Id$
******************************************************************/
#ifdef CORE_INLINE
// some helper functions.
CORE_INLINE void lidia_error_handler(const char *f, const char *m)
{
std::cout << "\n error_handler";
std::cout << "::" << f;
std::cout << "::" << m;
std::cout << "\n";
std::cout.flush();
abort();
}
CORE_INLINE void memory_handler(char *t, const char *f, const char *m)
{
if (t == NULL) {
std::cout << "\n memory_handler";
std::cout << "::" << f;
std::cout << "::" << m;
std::cout << "memory exhausted\n";
std::cout.flush();
abort();
}
}
/**
** constructors and destructor; we could leave out some of these
**/
CORE_INLINE bigint::bigint()
{ mpz_init(I); }
CORE_INLINE bigint::bigint(int i)
{ mpz_init_set_si(I, i); }
CORE_INLINE bigint::bigint(unsigned int ui)
{ mpz_init_set_ui(I, ui); }
CORE_INLINE bigint::bigint(long l)
{ mpz_init_set_si(I, l); }
CORE_INLINE bigint::bigint(unsigned long ul)
{ mpz_init_set_ui(I, ul); }
CORE_INLINE void bigint::assign(double d)
{ mpz_set_d(I, d); }
// new constructor
CORE_INLINE bigint::bigint(const char *str)
{ mpz_init_set_str(I, str, 0); }
CORE_INLINE bigint::bigint(const mpz_t & a)
{ mpz_init_set(I, a); }
CORE_INLINE bigint::bigint(const bigint & a)
{ mpz_init_set(I, a.I); }
CORE_INLINE bigint::~bigint()
{ mpz_clear(I); }
/**
** CORE_INLINE member functions
**/
CORE_INLINE int bigint::bit(unsigned int i) const
{ return mpz_tstbit(I, i); }
CORE_INLINE int bigint::length() const
{ return mpz_size(I); }
CORE_INLINE int bigint::bit_length() const
{ return mpz_sizeinbase(I, 2); }
CORE_INLINE int bigint::sign() const
{ return mpz_sgn(I); }
CORE_INLINE bool bigint::is_positive() const
{ return mpz_sgn(I) > 0; }
CORE_INLINE bool bigint::is_negative() const
{ return mpz_sgn(I) < 0; }
CORE_INLINE bool bigint::is_even() const
{ return mpz_even_p(I); }
CORE_INLINE bool bigint::is_odd() const
{ return mpz_odd_p(I); }
CORE_INLINE bool bigint::is_zero() const
{ return mpz_sgn(I) == 0; }
CORE_INLINE bool bigint::is_gt_zero() const
{ return mpz_sgn(I) > 0; }
CORE_INLINE bool bigint::is_ge_zero() const
{ return mpz_sgn(I) >= 0; }
CORE_INLINE bool bigint::is_lt_zero() const
{ return mpz_sgn(I) < 0; }
CORE_INLINE bool bigint::is_le_zero() const
{ return mpz_sgn(I) <= 0; }
CORE_INLINE bool bigint::is_one() const
{ return mpz_cmp_ui(I, 1) == 0; }
CORE_INLINE bool is_positive (const bigint & a)
{ return mpz_sgn(a.I) > 0; }
CORE_INLINE bool is_negative (const bigint & a)
{ return mpz_sgn(a.I) < 0; }
CORE_INLINE bool is_even (const bigint & a)
{ return mpz_even_p(a.I); }
CORE_INLINE bool is_odd (const bigint & a)
{ return mpz_odd_p(a.I); }
CORE_INLINE bool is_zero (const bigint & a)
{ return mpz_sgn(a.I) == 0; }
CORE_INLINE bool is_one (const bigint & a)
{ return mpz_cmp_ui(a.I, 1) == 0; }
CORE_INLINE bool bigint::intify(int & i) const
{
if (!mpz_fits_sint_p(I))
return 1;
i = (int) mpz_get_si(I);
return 0;
}
CORE_INLINE bool bigint::longify(long & i) const
{
if (!mpz_fits_slong_p(I))
return 1;
i = mpz_get_si(I);
return 0;
}
CORE_INLINE int bigint::abs_compare(const bigint & a) const
{
int cmp = mpz_cmpabs(I, a.I);
if (cmp < 0) return -1;
return (cmp > 0);
}
CORE_INLINE int bigint::compare(const bigint & a) const
{
int cmp = mpz_cmp(I, a.I);
if (cmp < 0) return -1;
return (cmp > 0);
}
CORE_INLINE unsigned long bigint::most_significant_digit() const
{
long l = mpz_size(I);
if (l == 0)
return 0;
return I[0]._mp_d[l - 1];
}
CORE_INLINE unsigned long bigint::least_significant_digit() const
{
if (mpz_sgn(I) == 0)
return 0;
return I[0]._mp_d[0];
}
CORE_INLINE const double bigint::radix()
{ return ldexp(1.0, mp_bits_per_limb); }
CORE_INLINE const int bigint::bits_per_digit()
{ return mp_bits_per_limb; }
CORE_INLINE void bigint::absolute_value()
{ mpz_abs(I, I); }
CORE_INLINE void bigint::abs()
{ mpz_abs(I, I); }
CORE_INLINE void bigint::negate()
{ mpz_neg(I, I); }
CORE_INLINE void bigint::assign_zero()
{ mpz_set_ui(I, 0); }
CORE_INLINE void bigint::assign_one()
{ mpz_set_ui(I, 1); }
CORE_INLINE void bigint::assign(int i)
{ mpz_set_si(I, i); }
CORE_INLINE void bigint::assign(long i)
{ mpz_set_si(I, i); }
CORE_INLINE void bigint::assign(unsigned long ui)
{ mpz_set_ui(I, ui); }
CORE_INLINE void bigint::assign(const bigint & a)
{ mpz_set(I, a.I); }
CORE_INLINE void bigint::multiply_by_2()
{ mpz_mul_2exp(I, I, 1); }
CORE_INLINE void bigint::divide_by_2()
{ mpz_tdiv_q_2exp(I, I, 1); }
/**
** Type checking
**/
CORE_INLINE bool is_char(const bigint & a)
{ return a.bit_length() <= (BITS_PER_CHAR - 1); }
CORE_INLINE bool is_uchar(const bigint & a)
{ return ( a.bit_length() <= (BITS_PER_CHAR) && !a.is_negative() ); }
CORE_INLINE bool is_short(const bigint & a)
{ return mpz_fits_sshort_p(a.I); }
CORE_INLINE bool is_ushort(const bigint & a)
{ return mpz_fits_ushort_p(a.I); }
CORE_INLINE bool is_int(const bigint & a)
{ return mpz_fits_sint_p(a.I); }
CORE_INLINE bool is_uint(const bigint & a)
{ return mpz_fits_uint_p(a.I); }
CORE_INLINE bool is_long(const bigint & a)
{ return mpz_fits_slong_p(a.I); }
CORE_INLINE bool is_ulong(const bigint & a)
{ return mpz_fits_ulong_p(a.I); }
/**
** assignments
**/
CORE_INLINE int bigint::operator = (int i)
{ mpz_set_si(I, i); return i; }
CORE_INLINE long bigint::operator = (long l)
{ mpz_set_si(I, l); return l; }
CORE_INLINE unsigned long bigint::operator = (unsigned long ul)
{ mpz_set_ui(I, ul); return ul; }
CORE_INLINE double bigint::operator = (double d)
{
mpz_set_d(I, d);
return d;
}
CORE_INLINE bigint & bigint::operator = (const bigint & a)
{
if (this == &a) // Bug fixed: avoid self-assignment
return *this; // Zilin Du, 07/11/01
mpz_set(I, a.I); return *this; }
/**
** comparisons
**/
CORE_INLINE bool operator == (const bigint & a, const bigint & b)
{ return mpz_cmp(a.I, b.I) == 0;}
CORE_INLINE bool operator != (const bigint & a, const bigint & b)
{ return mpz_cmp(a.I, b.I) != 0;}
CORE_INLINE bool operator > (const bigint & a, const bigint & b)
{ return mpz_cmp(a.I, b.I) > 0;}
CORE_INLINE bool operator >= (const bigint & a, const bigint & b)
{ return mpz_cmp(a.I, b.I) >= 0;}
CORE_INLINE bool operator < (const bigint & a, const bigint & b)
{ return mpz_cmp(a.I, b.I) < 0;}
CORE_INLINE bool operator <= (const bigint & a, const bigint & b)
{ return mpz_cmp(a.I, b.I) <= 0;}
/**
** operator overloading
**/
CORE_INLINE bigint operator - (const bigint & a)
{ bigint c; mpz_neg(c.I, a.I); return c; }
CORE_INLINE bigint operator + (const bigint & a, const bigint & b)
{ bigint c; mpz_add(c.I, a.I, b.I); return c; }
CORE_INLINE bigint operator - (const bigint & a, const bigint & b)
{ bigint c; mpz_sub(c.I, a.I, b.I); return c; }
CORE_INLINE bigint operator * (const bigint & a, const bigint & b)
{ bigint c; mpz_mul(c.I, a.I, b.I); return c; }
CORE_INLINE bigint operator / (const bigint & a, const bigint & b)
{ bigint c; mpz_tdiv_q(c.I, a.I, b.I); return c; }
CORE_INLINE bigint operator % (const bigint & a, const bigint & b)
{
bigint c;
mpz_mod(c.I, a.I, b.I); // returns non-negative rest c
if (a < 0 && c != 0)
{
// a is negative and rest != 0 -> create negative rest
if (b < 0)
mpz_add(c.I, c.I, b.I);
else
mpz_sub(c.I, c.I, b.I);
}
return c;
}
CORE_INLINE bigint operator << (const bigint & a, long ui)
{
bigint c;
if (ui < 0) {
#ifdef DEBUG
lidia_error_handler("bigint", "operator<<::index is negative.");
#endif
return (a >> (-ui));
}
mpz_mul_2exp(c.I, a.I, ui);
return c;
}
CORE_INLINE bigint operator >> (const bigint & a, long ui)
{
bigint c;
if (ui < 0) {
#ifdef DEBUG
lidia_error_handler("bigint", "operator>>::index is negative.");
#endif
return (a << (-ui));
}
mpz_tdiv_q_2exp(c.I, a.I, ui);
return c;
}
CORE_INLINE bigint operator & (const bigint & a, const bigint & b)
{ bigint c; mpz_and(c.I, a.I, b.I); return c; }
CORE_INLINE bigint operator | (const bigint & a, const bigint & b)
{ bigint c; mpz_ior(c.I, a.I, b.I); return c; }
CORE_INLINE bigint operator ^ (const bigint & a, const bigint & b)
{ bigint c = (a & ~b) | (~a & b); return c; }
CORE_INLINE bigint & bigint::operator += (const bigint & a)
{ mpz_add(I, I, a.I); return *this; }
CORE_INLINE bigint & bigint::operator -= (const bigint & a)
{ mpz_sub(I, I, a.I); return *this; }
CORE_INLINE bigint & bigint::operator *= (const bigint & a)
{ mpz_mul(I, I, a.I); return *this; }
CORE_INLINE bigint & bigint::operator /= (const bigint & a)
{ mpz_tdiv_q(I, I, a.I); return *this; }
CORE_INLINE bigint & bigint::operator %= (const bigint & a)
{
if (&a == this)
assign_zero();
else
{
bool is_neg = (*this < 0);
mpz_mod(I, I, a.I); // *this = *this % |a|
if (*this != 0)
{
if (a < 0) // create negative rest
mpz_add(I, I, a.I);
else if (is_neg)
mpz_sub(I, I, a.I);
}
}
return *this;
}
CORE_INLINE bigint & bigint::operator <<= (long ui)
{
if (ui < 0)
lidia_error_handler("bigint", "operator<<=::index is negative.");
mpz_mul_2exp(I, I, ui);
return *this;
}
CORE_INLINE bigint & bigint::operator >>= (long ui)
{
if (ui < 0)
lidia_error_handler("bigint", "operator>>=::index is negative.");
mpz_tdiv_q_2exp(I, I, ui);
return *this;
}
CORE_INLINE bigint & bigint::operator &= (const bigint & a)
{ mpz_and(I, I, a.I); return *this; }
CORE_INLINE bigint & bigint::operator |= (const bigint & a)
{ mpz_ior(I, I, a.I); return *this; }
CORE_INLINE bigint & bigint::operator ^= (const bigint & a)
{ mpz_xor(I, I, a.I); return *this; }
CORE_INLINE bigint & bigint::operator++ ()
{ mpz_add_ui(I, I, 1); return *this; }
CORE_INLINE bigint & bigint::operator-- ()
{ mpz_sub_ui(I, I, 1); return *this; }
CORE_INLINE bigint bigint::operator++ (int)
{ bigint a = *this; mpz_add_ui(I, I, 1); return a; }
CORE_INLINE bigint bigint::operator-- (int)
{ bigint a =*this; mpz_sub_ui(I, I, 1); return a; }
CORE_INLINE int bigint::operator ! () const
{ return mpz_size(I) == 0; }
CORE_INLINE bigint bigint::operator ~ () const
{ bigint c; mpz_com(c.I, I); return c; }
/**
** Procedural versions
**/
//CORE_INLINE void negate(bigint & a, const bigint & b)
//{ mpz_neg(a.I, b.I); }
CORE_INLINE void add(bigint & c, const bigint & a, const bigint & b)
{ mpz_add(c.I, a.I, b.I); }
CORE_INLINE void subtract(bigint & c, const bigint & a, const bigint & b)
{ mpz_sub(c.I, a.I, b.I); }
CORE_INLINE void multiply(bigint & c, const bigint & a, const bigint & b)
{ mpz_mul(c.I, a.I, b.I); }
CORE_INLINE void divide(bigint & c, const bigint & a, const bigint & b)
{ mpz_tdiv_q(c.I, a.I, b.I); }
CORE_INLINE void div_rem(bigint & q, bigint & r, const bigint & a, const bigint & b)
{ mpz_tdiv_qr(q.I, r.I, a.I, b.I); }
CORE_INLINE void invert(bigint & a, const bigint & b)
{
if (mpz_cmpabs_ui(b.I, 1) == 0) // b == 1 or b == -1.
mpz_set(a.I, b.I);
else
lidia_error_handler("bigint", "invert::inverting of a non-unit.");
}
CORE_INLINE void shift_left(bigint & c, const bigint & a, long ui)
{
if (ui < 0)
lidia_error_handler("bigint", "shift_left()::index is negative.");
mpz_mul_2exp(c.I, a.I, ui);
}
CORE_INLINE void shift_right(bigint & c, const bigint & a, long ui)
{
if (ui < 0)
lidia_error_handler("bigint", "shift_right()::index is negative.");
mpz_tdiv_q_2exp(c.I, a.I, ui);
}
/*CORE_INLINE void and(bigint & c, const bigint & a, const bigint & b)
{ mpz_and(c.I, a.I, b.I); }
CORE_INLINE void or(bigint & c, const bigint & a, const bigint & b)
{ mpz_ior(c.I, a.I, b.I); }
CORE_INLINE void xor(bigint & c, const bigint & a, const bigint & b)
{ c = (~a & b) | (~b & a); }
CORE_INLINE void not(bigint & b, const bigint & a)
{ mpz_com(b.I, a.I); }
*/
CORE_INLINE void inc(bigint & c)
{ mpz_add_ui(c.I, c.I, 1); }
CORE_INLINE void dec(bigint & c)
{ mpz_sub_ui(c.I, c.I, 1); }
CORE_INLINE void add(bigint & c, const bigint & a, long i)
{
if (i >= 0)
mpz_add_ui(c.I, a.I, i);
else
mpz_sub_ui(c.I, a.I, -i);
}
CORE_INLINE void subtract(bigint & c, const bigint & a, long i)
{
if (i >= 0)
mpz_sub_ui(c.I, a.I, i);
else
mpz_add_ui(c.I, a.I, -i);
}
CORE_INLINE void multiply(bigint & c, const bigint & a, long i)
{
if (i >= 0)
mpz_mul_ui(c.I, a.I, i);
else
{
mpz_mul_ui(c.I, a.I, -i);
mpz_neg(c.I, c.I);
}
}
CORE_INLINE void divide(bigint & q, const bigint & a, long i)
{
if (i > 0)
mpz_tdiv_q_ui(q.I, a.I, (unsigned long)i);
else
{
mpz_tdiv_q_ui(q.I, a.I, (unsigned long)(-i));
mpz_neg(q.I, q.I);
}
}
CORE_INLINE void remainder(long &r, const bigint & a, long i)
{
if (i > 0)
r = (long)mpz_tdiv_ui(a.I, i);
else
r = (long)mpz_tdiv_ui(a.I, -i);
if (r != 0 && mpz_sgn(a.I) < 0) // r must be negative
r = -r;
}
CORE_INLINE void remainder(unsigned long &r, const bigint & a, unsigned long i)
{ r = mpz_tdiv_ui(a.I, i); }
CORE_INLINE long remainder(const bigint & a, long i)
{
long r;
if (i > 0)
r = (long)mpz_tdiv_ui(a.I, i);
else
r = (long)mpz_tdiv_ui(a.I, -i);
if (r != 0 && mpz_sgn(a.I) < 0) // r must be negative
r = -r;
return r;
}
CORE_INLINE void div_rem(bigint & q, long &r, const bigint & a, long i)
{
if (i > 0)
r = (long) mpz_tdiv_q_ui(q.I, a.I, (unsigned long)i);
else
{
r = (long) mpz_tdiv_q_ui(q.I, a.I, (unsigned long)(-i));
mpz_neg(q.I, q.I);
}
if (r != 0 && mpz_sgn(a.I) < 0) // r must be negative
r = -r;
}
/**
** gcd's
**/
CORE_INLINE bigint gcd(const bigint & a, const bigint & b)
{ bigint c; mpz_gcd(c.I, a.I, b.I); return c; }
CORE_INLINE bigint bgcd(const bigint & a, const bigint & b)
{ bigint c; mpz_gcd(c.I, a.I, b.I); return c; }
CORE_INLINE bigint dgcd(const bigint & a, const bigint & b)
{ bigint c; mpz_gcd(c.I, a.I, b.I); return c; }
CORE_INLINE bigint xgcd(bigint & u, bigint & v, const bigint & a, const bigint & b)
{ bigint c; mpz_gcdext(c.I, u.I, v.I, a.I, b.I); return c; }
CORE_INLINE bigint xgcd_left(bigint & u, const bigint & a, const bigint & b)
{ bigint c; mpz_gcdext(c.I, u.I, 0, a.I, b.I); return c;}
CORE_INLINE bigint xgcd_right(bigint & v, const bigint & a, const bigint & b)
{ bigint c; mpz_gcdext(c.I, v.I, 0, b.I, a.I); return c; }
/**
** functions
**/
CORE_INLINE bigint abs(const bigint & a)
{ bigint c; mpz_abs(c.I, a.I); return c; }
CORE_INLINE static gmp_randstate_t * get_randstate()
{
static gmp_randstate_t rstate;
static bool initialized = false;
if (!initialized)
{
gmp_randinit(rstate, GMP_RAND_ALG_DEFAULT, 32L);
initialized = true;
}
return &rstate;
}
CORE_INLINE void seed(const bigint & a)
{
mpz_t tmp;
mpz_init_set(tmp, a.I);
gmp_randseed(*get_randstate(), tmp);
mpz_clear(tmp);
}
CORE_INLINE void bigint::randomize(const bigint & a)
{
if (a.is_zero())
lidia_error_handler("bigint", "Bound must not be equal to zero.");
else
{
bigint tmp;
mpz_urandomb(tmp.I, *get_randstate(), mpz_sizeinbase(a.I, 2));
if (a.is_lt_zero())
{
if (tmp <= a)
remainder(tmp, tmp, a);
}
else if (tmp >= a)
remainder(tmp, tmp, a);
swap(*this, tmp);
}
}
CORE_INLINE bigint randomize(const bigint & a)
{
bigint c;
c.randomize(a);
return c;
}
#ifdef USE_OLD_DBL
CORE_INLINE double dbl(const bigint & a)
{
char *s;
int t = (int) mpz_sizeinbase(&a.I, 10) + 2;
s = new char [t];
mpz_get_str(s, 10, &a.I);
double d;
d = atof(s);
delete[] s;
return d;
}
/*xdouble xdbl(const bigint & a)
{
char *s;
int t = (int) mpz_sizeinbase(&a.I, 10) + 2;
s = new char [t];
mpz_get_str(s, 10, &a.I);
xdouble d;
d = string_to_xdouble(s);
delete[] s;
return d;
}*/
#else
CORE_INLINE double dbl(const bigint & a)
{ return mpz_get_d(a.I); }
/*xdouble xdbl(const bigint & a)
{
long l = a.I._mp_size;
l=((l<0)?-l:l);
xdouble d = 0.0;
if (l)
{
int i = 1;
d = (double )a.I._mp_d[0];
xdouble base = bigint::radix();
xdouble power = base;
while (i < l)
{
d += a.I._mp_d[i] * power;
power *= base;
i++;
}
if (a.I._mp_size < 0)
d = -d;
}
return d;
}*/
#endif
CORE_INLINE void sqrt(bigint & a, const bigint & b)
{
if (b.is_lt_zero())
lidia_error_handler("bigint","sqrt(bigint&a,const bigint&b):: b < 0");
else
mpz_sqrt(a.I, b.I);
}
CORE_INLINE void square(bigint & a, const bigint & b)
{ mpz_mul(a.I, b.I, b.I); }
CORE_INLINE void swap(bigint & a, bigint & b)
{ mpz_swap(a.I, b.I); }
/**
** input / output
**/
CORE_INLINE std::istream & operator >> (std::istream & in, bigint & a)
{
a.scan (in);
return (in);
}
CORE_INLINE std::ostream & operator << (std::ostream & out, const bigint & a)
{
int l = (int) mpz_sizeinbase(a.I, 10) + 10;
char *s = new char [l];
mpz_get_str(s, 10, a.I);
a.print(out,s);
delete[] s;
return out;
}
CORE_INLINE int string_to_bigint(const char *s, bigint & a, int base)
{
if (!mpz_set_str(a.I, s, base))
return (strlen(s));
else
return 0;
}
CORE_INLINE int bigint_to_string(const bigint & a, char *s, int base)
{ mpz_get_str(s, base, a.I); return strlen(s); }
/**
** input / output
**/
// number of characters in one line
// when printing a bigint
CORE_INLINE void bigint
::set_chars_per_line (int cpl)
{
bigint::chars_per_line = cpl;
}
CORE_INLINE int bigint
::get_chars_per_line ()
{
return bigint::chars_per_line;
}
//
// characteristic
//
CORE_INLINE bigint bigint
::characteristic() const
{
return 0;
}
/*****************************************************************
* Core Additions to LiDIA's definitions above
*****************************************************************/
// This function is dangerous: if bigint a does fit into
// machine long, then tmp is set to zero.
CORE_INLINE long bigIntToLong(const bigint & a) {
long tmp;
if (a.longify(tmp)) // a.longify(tmp) returns 1 if
// a does not fit into a long, and tmp is unassigned.
tmp = 0;
// Otherwise a.longify(tmp) returns 0.
return tmp;
}
// Probably dangerous too:
CORE_INLINE double bigIntToDouble(const bigint & a) {
return dbl(a);
}
// lg(a) returns the bitlength of the argument a
//
// N.B. The name "lg" suggest that this is log to base 2.
// But it is a misnomer! The function "lg(a)" really computes
// the bitlength of |a|, i.e., "ceiling(log_2(1 + |a| ))"
// This function is deprecated.
CORE_INLINE int lg(const bigint & a){ // lg(a) = ceil(log_2(1+ |a|))
return a.bit_length(); // Note: sign is ignored.
}
// This is a more self-descriptive name for the previous "lg()"
// USE THIS NAME in place of lg().
CORE_INLINE int bitLength(const bigint & a){
// bitLength(a) = ceil(log_2(1+ |a|))
return a.bit_length();
}
CORE_INLINE int ceilLg(const bigint & a) { // this is ceiling of log_2(a):
// CONVENTION: log_2(0) = -1 (slight improvement, Zilin 8/5/02)
if (a.is_zero()) return -1;
unsigned int len = a.bit_length();
return (mpz_scan0(a.I, 0) == len-1) ? (len-1) : len;
}
CORE_INLINE int floorLg(const bigint & a) { // this is floor of log_2(a)
// CONVENTION: log_2(0) = -1 (slight improvement, Zilin 8/5/02)
if (a.is_zero()) return -1;
int len = a.bit_length();
return (len - 1);
}
CORE_INLINE int compare(const bigint &a, const bigint &b){ return a.compare(b);}
CORE_INLINE int sign(const bigint &a) { return a.sign(); }
#endif