/*****************************************************************************

  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
  more contributor license agreements.  See the NOTICE file distributed
  with this work for additional information regarding copyright ownership.
  Accellera licenses this file to you under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with the
  License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  implied.  See the License for the specific language governing
  permissions and limitations under the License.

 *****************************************************************************/

/*****************************************************************************

  sc_nbcommon.cpp -- Functions common to both sc_signed and sc_unsigned.
                     This file is included in sc_signed.cpp and
                     sc_unsigned.cpp after the macros are defined accordingly.
                     For example, sc_signed.cpp will first define CLASS_TYPE
                     as sc_signed before including this file. This file like
                     sc_nbfriends.cpp and sc_nbexterns.cpp is created in order
                     to ensure only one version of each function, regardless
                     of the class that they interface to.

  Original Author: Ali Dasdan, Synopsys, Inc.

 *****************************************************************************/

/*****************************************************************************

  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
  changes you are making here.

      Name, Affiliation, Date:
  Description of Modification:

 *****************************************************************************/


// ----------------------------------------------------------------------------
//  SECTION : Public members
// ----------------------------------------------------------------------------

// Create a CLASS_TYPE number with nb bits.
CLASS_TYPE::CLASS_TYPE(int nb) :
    sc_value_base(), sgn(), nbits(), ndigits(), digit()
{
    sgn = default_sign();
    if (nb > 0) {
	nbits = num_bits(nb);
    } else {
        invalid_init("int nb", nb);
        sc_core::sc_abort(); // can't recover from here
    }
    ndigits = DIV_CEIL(nbits);
#ifdef SC_MAX_NBITS
    test_bound(nb);
#else
    digit = new sc_digit[ndigits];
#endif
    makezero();
}


// Create a copy of v with sgn s. v is of the same type.
CLASS_TYPE::CLASS_TYPE(const CLASS_TYPE &v) :
    sc_value_base(v), sgn(v.sgn), nbits(v.nbits), ndigits(v.ndigits), digit()
{
#ifndef SC_MAX_NBITS
  digit = new sc_digit[ndigits];
#endif

  vec_copy(ndigits, digit, v.digit);
}


// Create a copy of v where v is of the different type.
CLASS_TYPE::CLASS_TYPE(const OTHER_CLASS_TYPE &v) :
    sc_value_base(v), sgn(v.sgn), nbits(num_bits(v.nbits)), ndigits(), digit()
{
#if (IF_SC_SIGNED == 1)
  ndigits = v.ndigits;
#else
  ndigits = DIV_CEIL(nbits);
#endif

#ifndef SC_MAX_NBITS
  digit = new sc_digit[ndigits];
#endif

  copy_digits(v.nbits, v.ndigits, v.digit);
}

// Create a copy of v where v is an sign-less instance.
CLASS_TYPE::CLASS_TYPE(const sc_bv_base &v) :
    sc_value_base(), sgn(), nbits(), ndigits(), digit()
{
    int nb = v.length();
    sgn = default_sign();
    if (nb > 0) {
        nbits = num_bits(nb);
    } else {
        invalid_init("sc_bv_base", nb);
        sc_core::sc_abort(); // can't recover from here
    }
    ndigits = DIV_CEIL(nbits);
#   ifdef SC_MAX_NBITS
        test_bound(nb);
#    else
        digit = new sc_digit[ndigits];
#    endif
    makezero();
    *this = v;
}

CLASS_TYPE::CLASS_TYPE(const sc_lv_base &v) :
    sc_value_base(), sgn(), nbits(), ndigits(), digit()
{
    int nb = v.length();
    sgn = default_sign();
    if (nb > 0) {
        nbits = num_bits(nb);
    } else {
        invalid_init("sc_lv_base", nb);
        sc_core::sc_abort(); // can't recover from here
    }
    ndigits = DIV_CEIL(nbits);
#   ifdef SC_MAX_NBITS
        test_bound(nb);
#    else
        digit = new sc_digit[ndigits];
#    endif
    makezero();
    *this = v;
}

CLASS_TYPE::CLASS_TYPE(const sc_int_subref_r &v) :
    sc_value_base(v), sgn(), nbits(), ndigits(), digit()
{
    int nb = v.length();
    sgn = default_sign();
    if (nb > 0) {
        nbits = num_bits(nb);
    } else {
        invalid_init("sc_int_subref", nb);
        sc_core::sc_abort(); // can't recover from here
    }
    ndigits = DIV_CEIL(nbits);
#   ifdef SC_MAX_NBITS
        test_bound(nb);
#    else
        digit = new sc_digit[ndigits];
#    endif
    makezero();
    *this = v.to_uint64();
}

CLASS_TYPE::CLASS_TYPE(const sc_uint_subref_r &v) :
    sc_value_base(v), sgn(), nbits(), ndigits(), digit()
{
    int nb = v.length();
    sgn = default_sign();
    if (nb > 0) {
        nbits = num_bits(nb);
    } else {
        invalid_init("sc_uint_subref", nb);
        sc_core::sc_abort(); // can't recover from here
    }
    ndigits = DIV_CEIL(nbits);
#   ifdef SC_MAX_NBITS
        test_bound(nb);
#    else
        digit = new sc_digit[ndigits];
#    endif
    makezero();
    *this = v.to_uint64();
}

CLASS_TYPE::CLASS_TYPE(const sc_signed_subref_r &v) :
    sc_value_base(v), sgn(), nbits(), ndigits(), digit()
{
    int nb = v.length();
    sgn = default_sign();
    if (nb > 0) {
        nbits = num_bits(nb);
    } else {
        invalid_init("sc_signed_subref", nb);
        sc_core::sc_abort(); // can't recover from here
    }
    ndigits = DIV_CEIL(nbits);
#   ifdef SC_MAX_NBITS
        test_bound(nb);
#    else
        digit = new sc_digit[ndigits];
#    endif
    makezero();
    *this = sc_unsigned(v.m_obj_p, v.m_left, v.m_right);
}

CLASS_TYPE::CLASS_TYPE(const sc_unsigned_subref_r &v) :
    sc_value_base(v), sgn(), nbits(), ndigits(), digit()
{
    int nb = v.length();
    sgn = default_sign();
    if (nb > 0) {
        nbits = num_bits(nb);
    } else {
        invalid_init("sc_unsigned_subref", nb);
        sc_core::sc_abort(); // can't recover from here
    }
    ndigits = DIV_CEIL(nbits);
#   ifdef SC_MAX_NBITS
        test_bound(nb);
#    else
        digit = new sc_digit[ndigits];
#    endif
    makezero();
    *this = sc_unsigned(v.m_obj_p, v.m_left, v.m_right);
}

// ----------------------------------------------------------------------------
//  SECTION: Public members - Concatenation support.
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
//  SECTION: Public members - Assignment operators.
// ----------------------------------------------------------------------------

// Assignment from v of the same type.
const CLASS_TYPE &
CLASS_TYPE::operator = (const CLASS_TYPE &v)
{
    if (this != &v) {
        sgn = v.sgn;

        if (sgn == SC_ZERO)
            vec_zero(ndigits, digit);
        else
            copy_digits(v.nbits, v.ndigits, v.digit);
    }
    return *this;
}


// Assignment from v of the different type.
const CLASS_TYPE &
CLASS_TYPE::operator = (const OTHER_CLASS_TYPE &v)
{
    sgn = v.sgn;

    if (sgn == SC_ZERO)
        vec_zero(ndigits, digit);
    else
        copy_digits(v.nbits, v.ndigits, v.digit);

    return *this;
}


// Assignment from an sc_unsigned_subref_r
const CLASS_TYPE &
CLASS_TYPE::operator = (const sc_unsigned_subref_r &v)
{
    return operator=(sc_unsigned(v));
}


// Assignment from an sc_signed_subref_r
const CLASS_TYPE &
CLASS_TYPE::operator = (const sc_signed_subref_r &v)
{
    return operator = (sc_unsigned(v));
}


// ----------------------------------------------------------------------------
//  SECTION: Input and output operators
// ----------------------------------------------------------------------------

void
CLASS_TYPE::scan(::std::istream &is)
{
    std::string s;
    is >> s;
    *this = s.c_str();
}


// ----------------------------------------------------------------------------
//  SECTION: PLUS operators: +, +=, ++
// ----------------------------------------------------------------------------

// Cases to consider when computing u + v:
// 1. 0 + v = v
// 2. u + 0 = u
// 3. if sgn(u) == sgn(v)
//    3.1 u + v = +(u + v) = sgn(u) * (u + v)
//    3.2 (-u) + (-v) = -(u + v) = sgn(u) * (u + v)
// 4. if sgn(u) != sgn(v)
//    4.1 u + (-v) = u - v = sgn(u) * (u - v)
//    4.2 (-u) + v = -(u - v) ==> sgn(u) * (u - v)
//
// Specialization of above cases for computing ++u or u++:
// 1. 0 + 1 = 1
// 3. u + 1 = u + 1 = sgn(u) * (u + 1)
// 4. (-u) + 1 = -(u - 1) = sgn(u) * (u - 1)

const CLASS_TYPE &
CLASS_TYPE::operator += (const CLASS_TYPE &v)
{
    // u = *this

    if (sgn == SC_ZERO) // case 1
        return (*this = v);

    if (v.sgn == SC_ZERO) // case 2
        return *this;

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                v.sgn, v.nbits, v.ndigits, v.digit);

    convert_SM_to_2C_to_SM();

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator += (const OTHER_CLASS_TYPE &v)
{
    // u = *this

    if (sgn == SC_ZERO) // case 1
        return (*this = v);

    if (v.sgn == SC_ZERO) // case 2
        return *this;

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                v.sgn, v.nbits, v.ndigits, v.digit);

    convert_SM_to_2C_to_SM();

    return *this;
}


CLASS_TYPE &
CLASS_TYPE::operator ++ () // prefix
{
    *this = *this + 1;
    return *this;
}


const CLASS_TYPE
CLASS_TYPE::operator ++ (int) // postfix
{
    // Copy digit into d.

#ifdef SC_MAX_NBITS
    sc_digit d[MAX_NDIGITS];
#else
    sc_digit *d = new sc_digit[ndigits];
#endif

    small_type s = sgn;

    vec_copy(ndigits, d, digit);

    *this = *this + 1;

    return CLASS_TYPE(s, nbits, ndigits, d);
}


const CLASS_TYPE &
CLASS_TYPE::operator += (int64 v)
{
    // u = *this

    if (sgn == SC_ZERO) // case 1
        return (*this = v);

    if (v == 0) // case 2
        return *this;

    CONVERT_INT64(v);

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);

    convert_SM_to_2C_to_SM();

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator += (uint64 v)
{
    // u = *this

    if (sgn == SC_ZERO) // case 1
        return (*this = v);

    if (v == 0)  // case 2
        return *this;

    CONVERT_INT64(v);

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);

    convert_SM_to_2C_to_SM();

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator += (long v)
{
    // u = *this

    if (sgn == SC_ZERO) // case 1
        return (*this = v);

    if (v == 0) // case 2
        return *this;

    CONVERT_LONG(v);

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);

    convert_SM_to_2C_to_SM();

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator += (unsigned long v)
{
    // u = *this

    if (sgn == SC_ZERO) // case 1
        return (*this = v);

    if (v == 0) // case 2
        return *this;

    CONVERT_LONG(v);

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);

    convert_SM_to_2C_to_SM();

    return *this;
}


// ----------------------------------------------------------------------------
//  SECTION: MINUS operators: -, -=, --
// ----------------------------------------------------------------------------

// Cases to consider when computing u + v:
// 1. u - 0 = u
// 2. 0 - v = -v
// 3. if sgn(u) != sgn(v)
//    3.1 u - (-v) = u + v = sgn(u) * (u + v)
//    3.2 (-u) - v = -(u + v) ==> sgn(u) * (u + v)
// 4. if sgn(u) == sgn(v)
//    4.1 u - v = +(u - v) = sgn(u) * (u - v)
//    4.2 (-u) - (-v) = -(u - v) = sgn(u) * (u - v)
//
// Specialization of above cases for computing --u or u--:
// 1. 0 - 1 = -1
// 3. (-u) - 1 = -(u + 1) = sgn(u) * (u + 1)
// 4. u - 1 = u - 1 = sgn(u) * (u - 1)

const CLASS_TYPE &
CLASS_TYPE::operator -= (const CLASS_TYPE &v)
{
    // u = *this
    if (v.sgn == SC_ZERO) // case 1
        return *this;
    if (sgn == SC_ZERO) { // case 2
        sgn = -v.sgn;
        copy_digits(v.nbits, v.ndigits, v.digit);
    } else {
        // cases 3 and 4
        add_on_help(sgn, nbits, ndigits, digit,
                  -v.sgn, v.nbits, v.ndigits, v.digit);
        convert_SM_to_2C_to_SM();
    }

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator -= (const OTHER_CLASS_TYPE &v)
{
    // u = *this
    if (v.sgn == SC_ZERO) // case 1
        return *this;
    if (sgn == SC_ZERO) { // case 2
        sgn = -v.sgn;
        copy_digits(v.nbits, v.ndigits, v.digit);
    } else {
        // cases 3 and 4
        add_on_help(sgn, nbits, ndigits, digit,
                  -v.sgn, v.nbits, v.ndigits, v.digit);

        convert_SM_to_2C_to_SM();
    }
    return *this;
}

CLASS_TYPE &
CLASS_TYPE::operator -- () // prefix
{
    *this = *this - 1;
    return *this;
}

const CLASS_TYPE
CLASS_TYPE::operator -- (int) // postfix
{
    // Copy digit into d.
#ifdef SC_MAX_NBITS
    sc_digit d[MAX_NDIGITS];
#else
    sc_digit *d = new sc_digit[ndigits];
#endif
    small_type s = sgn;
    vec_copy(ndigits, d, digit);
    *this = *this - 1;
    return CLASS_TYPE(s, nbits, ndigits, d);
}


const CLASS_TYPE &
CLASS_TYPE::operator -= (int64 v)
{
    // u = *this
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = -v);

    CONVERT_INT64(v);

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                -vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);

    convert_SM_to_2C_to_SM();

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator -= (uint64 v)
{
    // u = *this

    if (v == 0) // case 1
        return *this;

    int64 v2 = (int64) v;

    if (sgn == SC_ZERO) // case 2
        return (*this = -v2);

    CONVERT_INT64(v);

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                -vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);

    convert_SM_to_2C_to_SM();

    return *this;
}

const CLASS_TYPE &
CLASS_TYPE::operator -= (long v)
{
    // u = *this

    if (v == 0) // case 1
        return *this;

    if (sgn == SC_ZERO) // case 2
        return (*this = -v);

    CONVERT_LONG(v);

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                -vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);

    convert_SM_to_2C_to_SM();

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator -= (unsigned long v)
{
    // u = *this

    if (v == 0) // case 1
        return *this;

    long v2 = (long) v;

    if (sgn == SC_ZERO) // case 2
        return (*this = -v2);

    CONVERT_LONG(v);

    // cases 3 and 4
    add_on_help(sgn, nbits, ndigits, digit,
                -vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);

    convert_SM_to_2C_to_SM();

    return *this;
}


// ----------------------------------------------------------------------------
//  SECTION: MULTIPLICATION operators: *, *=
// ----------------------------------------------------------------------------

// Cases to consider when computing u * v:
// 1. u * 0 = 0 * v = 0
// 2. 1 * v = v and -1 * v = -v
// 3. u * 1 = u and u * -1 = -u
// 4. u * v = u * v

const CLASS_TYPE &
CLASS_TYPE::operator *= (const CLASS_TYPE &v)
{
    // u = *this

    sgn = mul_signs(sgn, v.sgn);

    if (sgn == SC_ZERO) { // case 1
        vec_zero(ndigits, digit);
    } else {
        // cases 2-4
        MUL_ON_HELPER(sgn,    nbits, ndigits, digit,
                      v.nbits, v.ndigits, v.digit);
    }

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator *= (const OTHER_CLASS_TYPE &v)
{
    // u = *this

    sgn = mul_signs(sgn, v.sgn);

    if (sgn == SC_ZERO) { // case 1
        vec_zero(ndigits, digit);
    } else {
        // cases 2-4
        MUL_ON_HELPER(sgn,    nbits, ndigits, digit,
                      v.nbits, v.ndigits, v.digit);
    }

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator *= (int64 v)
{
    // u = *this

    sgn = mul_signs(sgn, get_sign(v));

    if (sgn == SC_ZERO) { // case 1
        vec_zero(ndigits, digit);
    } else { // cases 2-4
        CONVERT_INT64_2(v);
        MUL_ON_HELPER(sgn, nbits, ndigits, digit,
                      BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    }

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator *= (uint64 v)
{
    // u = *this
    sgn = mul_signs(sgn, get_sign(v));

    if (sgn == SC_ZERO) { // case 1
        vec_zero(ndigits, digit);
    } else { // cases 2-4
        CONVERT_INT64_2(v);
        MUL_ON_HELPER(sgn,    nbits, ndigits, digit,
                      BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    }

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator *= (long v)
{
    // u = *this

    sgn = mul_signs(sgn, get_sign(v));

    if (sgn == SC_ZERO) { // case 1
        vec_zero(ndigits, digit);
    } else { // cases 2-4
        CONVERT_LONG_2(v);
        MUL_ON_HELPER(sgn,    nbits, ndigits, digit,
                      BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator *= (unsigned long v)
{
    // u = *this

    sgn = mul_signs(sgn, get_sign(v));

    if (sgn == SC_ZERO) { // case 1
        vec_zero(ndigits, digit);
    } else { // cases 2-4
        CONVERT_LONG_2(v);
        MUL_ON_HELPER(sgn,    nbits, ndigits, digit,
                      BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    }

    return *this;
}


// ----------------------------------------------------------------------------
//  SECTION: DIVISION operators: /, /=
// ----------------------------------------------------------------------------

// Cases to consider when finding the quotient q = floor(u/v):
// Note that u = q * v + r for r < q.
// 1. 0 / 0 or u / 0 => error
// 2. 0 / v => 0 = 0 * v + 0
// 3. u / v && u = v => u = 1 * u + 0  - u or v can be 1 or -1
// 4. u / v && u < v => u = 0 * v + u  - u can be 1 or -1
// 5. u / v && u > v => u = q * v + r  - v can be 1 or -1

const CLASS_TYPE &
CLASS_TYPE::operator /= (const CLASS_TYPE &v)
{
    sgn = mul_signs(sgn, v.sgn);

    if (sgn == SC_ZERO) {
        div_by_zero(v.sgn); // case 1
        vec_zero(ndigits, digit); // case 2
    } else { // other cases
        DIV_ON_HELPER(sgn, nbits, ndigits, digit,
                      v.nbits, v.ndigits, v.digit);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator /= (const OTHER_CLASS_TYPE &v)
{
    sgn = mul_signs(sgn, v.sgn);

    if (sgn == SC_ZERO) {
        div_by_zero(v.sgn); // case 1
        vec_zero(ndigits, digit); // case 2
    } else { // other cases
        DIV_ON_HELPER(sgn, nbits, ndigits, digit,
                      v.nbits, v.ndigits, v.digit);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator /= (int64 v)
{
    // u = *this

    sgn = mul_signs(sgn, get_sign(v));

    if (sgn == SC_ZERO) {
        div_by_zero(v); // case 1
        vec_zero(ndigits, digit); // case 2
    } else {
        CONVERT_INT64_2(v);
        // other cases
        DIV_ON_HELPER(sgn, nbits, ndigits, digit,
                      BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator /= (uint64 v)
{
    // u = *this

    sgn = mul_signs(sgn, get_sign(v));

    if (sgn == SC_ZERO) {
        div_by_zero(v); // case 1
        vec_zero(ndigits, digit); // case 2
    } else {
        CONVERT_INT64_2(v);
        // other cases
        DIV_ON_HELPER(sgn, nbits, ndigits, digit,
                  BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator /= (long v)
{
    // u = *this

    sgn = mul_signs(sgn, get_sign(v));

    if (sgn == SC_ZERO) {
        div_by_zero(v); // case 1
        vec_zero(ndigits, digit); // case 2
    } else {
        CONVERT_LONG_2(v);
        // other cases
        DIV_ON_HELPER(sgn,    nbits, ndigits, digit,
                      BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator /= (unsigned long v)
{
    // u = *this

    sgn = mul_signs(sgn, get_sign(v));

    if (sgn == SC_ZERO) {
        div_by_zero(v); // case 1
        vec_zero(ndigits, digit); // case 2
    } else {
        CONVERT_LONG_2(v);
        // other cases
        DIV_ON_HELPER(sgn,    nbits, ndigits, digit,
                      BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    }
    return *this;
}


// ----------------------------------------------------------------------------
//  SECTION: MOD operators: %, %=.
// ----------------------------------------------------------------------------

// Cases to consider when finding the remainder r = u % v:
// Note that u = q * v + r for r < q.
// 1. 0 % 0 or u % 0 => error
// 2. 0 % v => 0 = 0 * v + 0
// 3. u % v && u = v => u = 1 * u + 0  - u or v can be 1 or -1
// 4. u % v && u < v => u = 0 * v + u  - u can be 1 or -1
// 5. u % v && u > v => u = q * v + r  - v can be 1 or -1

const CLASS_TYPE &
CLASS_TYPE::operator %= (const CLASS_TYPE &v)
{
    if ((sgn == SC_ZERO) || (v.sgn == SC_ZERO)) {
        div_by_zero(v.sgn); // case 1
        vec_zero(ndigits, digit); // case 2
    } else { // other cases
        MOD_ON_HELPER(sgn, nbits, ndigits, digit,
                      v.nbits, v.ndigits, v.digit);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator %= (const OTHER_CLASS_TYPE &v)
{
    if ((sgn == SC_ZERO) || (v.sgn == SC_ZERO)) {
        div_by_zero(v.sgn); // case 1
        vec_zero(ndigits, digit); // case 2
    } else { // other cases
        MOD_ON_HELPER(sgn, nbits, ndigits, digit,
                      v.nbits, v.ndigits, v.digit);
    }

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator %= (int64 v)
{
    small_type vs = get_sign(v);

    if ((sgn == SC_ZERO) || (vs == SC_ZERO)) {
        div_by_zero(v); // case 1
        vec_zero(ndigits, digit); // case 2
    } else {
        CONVERT_INT64_2(v);
        // other cases
        MOD_ON_HELPER(sgn, nbits, ndigits, digit,
                      BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator %= (uint64 v)
{
    if ((sgn == SC_ZERO) || (v == 0)) {
        div_by_zero(v); // case 1
        vec_zero(ndigits, digit); // case 2
    } else {
        CONVERT_INT64_2(v);
        // other cases
        MOD_ON_HELPER(sgn, nbits, ndigits, digit,
                      BITS_PER_UINT64, DIGITS_PER_UINT64, vd);

    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator %= (long v)
{
    small_type vs = get_sign(v);

    if ((sgn == SC_ZERO) || (vs == SC_ZERO)) {
        div_by_zero(v); // case 1
        vec_zero(ndigits, digit); // case 2
    } else {
        CONVERT_LONG_2(v);
        // other cases
        MOD_ON_HELPER(sgn, nbits, ndigits, digit,
                      BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator %= (unsigned long v)
{
    if ((sgn == SC_ZERO) || (v == 0)) {
        div_by_zero(v); // case 1
        vec_zero(ndigits, digit); // case 2
    } else {
        CONVERT_LONG_2(v);
        // other cases
        MOD_ON_HELPER(sgn, nbits, ndigits, digit,
                      BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    }
    return *this;
}


// ----------------------------------------------------------------------------
//    SECTION: Bitwise AND operators: &, &=
// ----------------------------------------------------------------------------

// Cases to consider when computing u    &v:
// 1. u & 0 = 0    &v = 0
// 2. u    &v => sgn = +
// 3. (-u) & (-v) => sgn = -
// 4. u & (-v) => sgn = +
// 5. (-u)    &v => sgn = +

const CLASS_TYPE &
CLASS_TYPE::operator &= (const CLASS_TYPE &v)
{
    // u = *this
    if ((sgn == SC_ZERO) || (v.sgn == SC_ZERO)) { // case 1
        makezero();
    } else { // other cases
        and_on_help(sgn, nbits, ndigits, digit,
                    v.sgn, v.nbits, v.ndigits, v.digit);
        convert_2C_to_SM();
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator &= (const OTHER_CLASS_TYPE &v)
{
    // u = *this

    if ((sgn == SC_ZERO) || (v.sgn == SC_ZERO)) { // case 1
        makezero();
    } else { // other cases
        and_on_help(sgn, nbits, ndigits, digit,
                    v.sgn, v.nbits, v.ndigits, v.digit);
        convert_2C_to_SM();
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator &= (int64 v)
{
    // u = *this
    if ((sgn == SC_ZERO) || (v == 0)) { // case 1
        makezero();
    } else { // other cases
        CONVERT_INT64(v);
        and_on_help(sgn, nbits, ndigits, digit,
                    vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
        convert_2C_to_SM();
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator &= (uint64 v)
{
    // u = *this
    if ((sgn == SC_ZERO) || (v == 0)) { // case 1
        makezero();
    } else { // other cases
        CONVERT_INT64(v);
        and_on_help(sgn, nbits, ndigits, digit,
                    vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
        convert_2C_to_SM();
    }
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator &= (long v)
{
    // u = *this

    if ((sgn == SC_ZERO) || (v == 0)) { // case 1
        makezero();
    } else { // other cases
        CONVERT_LONG(v);
        and_on_help(sgn, nbits, ndigits, digit,
                    vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
        convert_2C_to_SM();
    }

    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator &= (unsigned long v)
{
    // u = *this
    if ((sgn == SC_ZERO) || (v == 0)) { // case 1
        makezero();
    } else { // other cases
        CONVERT_LONG(v);
        and_on_help(sgn, nbits, ndigits, digit,
                    vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
        convert_2C_to_SM();
    }
    return *this;
}


// ----------------------------------------------------------------------------
//    SECTION: Bitwise OR operators: |, |=
// ----------------------------------------------------------------------------

// Cases to consider when computing u | v:
// 1. u | 0 = u
// 2. 0 | v = v
// 3. u | v => sgn = +
// 4. (-u) | (-v) => sgn = -
// 5. u | (-v) => sgn = -
// 6. (-u) | v => sgn = -

const CLASS_TYPE &
CLASS_TYPE::operator |= (const CLASS_TYPE &v)
{
    if (v.sgn == SC_ZERO) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    or_on_help(sgn, nbits, ndigits, digit,
               v.sgn, v.nbits, v.ndigits, v.digit);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator |= (const OTHER_CLASS_TYPE &v)
{
    if (v.sgn == SC_ZERO) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    or_on_help(sgn, nbits, ndigits, digit,
               v.sgn, v.nbits, v.ndigits, v.digit);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE&
CLASS_TYPE::operator |= (int64 v)
{
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    CONVERT_INT64(v);
    or_on_help(sgn, nbits, ndigits, digit,
               vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE&
CLASS_TYPE::operator |= (uint64 v)
{
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    CONVERT_INT64(v);
    or_on_help(sgn, nbits, ndigits, digit,
               vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator |= (long v)
{
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    CONVERT_LONG(v);
    or_on_help(sgn, nbits, ndigits, digit,
               vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator |= (unsigned long v)
{
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    CONVERT_LONG(v);
    or_on_help(sgn, nbits, ndigits, digit,
               vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    convert_2C_to_SM();
    return *this;
}


// ----------------------------------------------------------------------------
//    SECTION: Bitwise XOR operators: ^, ^=
// ----------------------------------------------------------------------------

// Cases to consider when computing u ^ v:
// Note that    u ^ v = (~u    &v) | (u & ~v).
// 1. u ^ 0 = u
// 2. 0 ^ v = v
// 3. u ^ v => sgn = +
// 4. (-u) ^ (-v) => sgn = -
// 5. u ^ (-v) => sgn = -
// 6. (-u) ^ v => sgn = +

const CLASS_TYPE &
CLASS_TYPE::operator ^= (const CLASS_TYPE &v)
{
    // u = *this
    if (v.sgn == SC_ZERO) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    xor_on_help(sgn, nbits, ndigits, digit,
                v.sgn, v.nbits, v.ndigits, v.digit);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator ^= (const OTHER_CLASS_TYPE &v)
{
    // u = *this
    if (v.sgn == SC_ZERO) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    xor_on_help(sgn, nbits, ndigits, digit,
                v.sgn, v.nbits, v.ndigits, v.digit);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE&
CLASS_TYPE::operator ^= (int64 v)
{
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    CONVERT_INT64(v);
    xor_on_help(sgn, nbits, ndigits, digit,
                vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator ^= (uint64 v)
{
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    CONVERT_INT64(v);
    xor_on_help(sgn, nbits, ndigits, digit,
                vs, BITS_PER_UINT64, DIGITS_PER_UINT64, vd);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator ^= (long v)
{
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    CONVERT_LONG(v);
    xor_on_help(sgn, nbits, ndigits, digit,
                vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    convert_2C_to_SM();
    return *this;
}


const CLASS_TYPE &
CLASS_TYPE::operator ^= (unsigned long v)
{
    if (v == 0) // case 1
        return *this;
    if (sgn == SC_ZERO) // case 2
        return (*this = v);
    // other cases
    CONVERT_LONG(v);
    xor_on_help(sgn, nbits, ndigits, digit,
                vs, BITS_PER_ULONG, DIGITS_PER_ULONG, vd);
    convert_2C_to_SM();
    return *this;
}


// ----------------------------------------------------------------------------
//    SECTION: Bitwise NOT operator: ~
// ----------------------------------------------------------------------------

CLASS_TYPE
operator ~ (const CLASS_TYPE &u)
{
    small_type s = u.sgn;
    if (s == SC_ZERO) {
        sc_digit d = 1;
        return CLASS_TYPE(SC_NEG, u.nbits, 1, &d, false);
    }

    int nd = u.ndigits;

#ifdef SC_MAX_NBITS
    sc_digit d[MAX_NDIGITS];
#else
    sc_digit *d = new sc_digit[nd];
#endif

    vec_copy(nd, d, u.digit);
    if (s == SC_POS) {
        s = SC_NEG;
        vec_add_small_on(nd, d, 1);
    } else {
        s = SC_POS;
        vec_sub_small_on(nd, d, 1);
        if (check_for_zero(nd, d))
            s = SC_ZERO;
    }
    return CLASS_TYPE(s, u.nbits, nd, d);
}


// ----------------------------------------------------------------------------
//    SECTION: LEFT SHIFT operators: <<, <<=
// ----------------------------------------------------------------------------

CLASS_TYPE
operator << (const CLASS_TYPE &u, const CLASS_TYPE &v)
{
    if (v.sgn == SC_ZERO)
        return CLASS_TYPE(u);
#ifdef SC_SIGNED
    if (v.sgn == SC_NEG)
        return CLASS_TYPE(u);
#endif
    return operator << (u, v.to_ulong());
}


const CLASS_TYPE &
CLASS_TYPE::operator <<= (const CLASS_TYPE &v)
{
    if (v.sgn == SC_ZERO)
        return *this;
#ifdef SC_SIGNED
    if (v.sgn == SC_NEG)
        return *this;
#endif
    return operator <<= (v.to_ulong());
}


const CLASS_TYPE &
CLASS_TYPE::operator <<= (const OTHER_CLASS_TYPE &v)
{
    if (v.sgn == SC_ZERO)
        return *this;
#ifdef SC_UNSIGNED
    if (v.sgn == SC_NEG)
        return *this;
#endif
    return operator <<= (v.to_ulong());
}


CLASS_TYPE
operator << (const CLASS_TYPE &u, int64 v)
{
    if (v <= 0)
        return CLASS_TYPE(u);
    return operator << (u, (unsigned long)v);
}


CLASS_TYPE
operator << (const CLASS_TYPE &u, uint64 v)
{
    if (v == 0)
        return CLASS_TYPE(u);
    return operator << (u, (unsigned long)v);
}


const CLASS_TYPE &
CLASS_TYPE::operator <<= (int64 v)
{
    if (v <= 0)
        return *this;
    return operator <<= ((unsigned long)v);
}


const CLASS_TYPE &
CLASS_TYPE::operator <<= (uint64 v)
{
    if (v == 0)
        return *this;
    return operator <<= ((unsigned long)v);
}


CLASS_TYPE
operator << (const CLASS_TYPE &u, long v)
{
    if (v <= 0)
        return CLASS_TYPE(u);
    return operator << (u, (unsigned long)v);
}

CLASS_TYPE
operator << (const CLASS_TYPE &u, unsigned long v)
{
    if (v == 0)
        return CLASS_TYPE(u);
    if (u.sgn == SC_ZERO)
        return CLASS_TYPE(u);

    int nb = u.nbits + v;
    int nd = DIV_CEIL(nb);

#ifdef SC_MAX_NBITS
    test_bound(nb);
    sc_digit d[MAX_NDIGITS];
#else
    sc_digit *d = new sc_digit[nd];
#endif

    vec_copy_and_zero(nd, d, u.ndigits, u.digit);
    convert_SM_to_2C(u.sgn, nd, d);
    vec_shift_left(nd, d, v);
    small_type s = convert_signed_2C_to_SM(nb, nd, d);
    return CLASS_TYPE(s, nb, nd, d);
}


const CLASS_TYPE &
CLASS_TYPE::operator <<= (long v)
{
    if (v <= 0)
        return *this;
    return operator <<= ((unsigned long)v);
}


const CLASS_TYPE &
CLASS_TYPE::operator <<= (unsigned long v)
{
    if (v == 0)
        return *this;
    if (sgn == SC_ZERO)
        return *this;
    convert_SM_to_2C();
    vec_shift_left(ndigits, digit, v);
    convert_2C_to_SM();
    return *this;
}


// ----------------------------------------------------------------------------
//    SECTION: RIGHT SHIFT operators: >>, >>=
// ----------------------------------------------------------------------------

CLASS_TYPE
operator >> (const CLASS_TYPE &u, const CLASS_TYPE &v)
{
    if (v.sgn == SC_ZERO)
        return CLASS_TYPE(u);
#ifdef SC_SIGNED
    if (v.sgn == SC_NEG)
        return CLASS_TYPE(u);
#endif
    return operator >> (u, v.to_long());
}


const CLASS_TYPE &
CLASS_TYPE::operator >>= (const CLASS_TYPE &v)
{
    if (v.sgn == SC_ZERO)
        return *this;
#ifdef SC_SIGNED
    if (v.sgn == SC_NEG)
        return *this;
#endif
    return operator >>= (v.to_long());
}


const CLASS_TYPE &
CLASS_TYPE::operator >>= (const OTHER_CLASS_TYPE &v)
{
    if (v.sgn == SC_ZERO)
        return *this;
#ifdef SC_UNSIGNED
    if (v.sgn == SC_NEG)
        return *this;
#endif
    return operator >>= (v.to_ulong());
}


CLASS_TYPE
operator >> (const CLASS_TYPE &u, int64 v)
{
    if (v <= 0)
        return CLASS_TYPE(u);
    return operator >> (u, (unsigned long)v);
}


CLASS_TYPE
operator >> (const CLASS_TYPE &u, uint64 v)
{
    if (v == 0)
        return CLASS_TYPE(u);
    return operator >> (u, (unsigned long)v);
}

const CLASS_TYPE &
CLASS_TYPE::operator >>= (int64 v)
{
    if (v <= 0)
        return *this;
    return operator >>= ((unsigned long)v);
}


const CLASS_TYPE &
CLASS_TYPE::operator >>= (uint64 v)
{
    if (v == 0)
        return *this;
    return operator >>= ((unsigned long)v);
}


CLASS_TYPE
operator >> (const CLASS_TYPE &u, long v)
{
    if (v <= 0)
        return CLASS_TYPE(u);
    return operator >> (u, (unsigned long)v);
}


CLASS_TYPE
operator >> (const CLASS_TYPE &u, unsigned long v)
{
    if (v == 0)
        return CLASS_TYPE(u);
    if (u.sgn == SC_ZERO)
        return CLASS_TYPE(u);

    int nb = u.nbits;
    int nd = u.ndigits;

#ifdef SC_MAX_NBITS
    sc_digit d[MAX_NDIGITS];
#else
    sc_digit *d = new sc_digit[nd];
#endif

    vec_copy(nd, d, u.digit);
    convert_SM_to_2C(u.sgn, nd, d);
    if (u.sgn == SC_NEG)
        vec_shift_right(nd, d, v, DIGIT_MASK);
    else
        vec_shift_right(nd, d, v, 0);
    small_type s = convert_signed_2C_to_SM(nb, nd, d);
    return CLASS_TYPE(s, nb, nd, d);
}


const CLASS_TYPE &
CLASS_TYPE::operator >>= (long v)
{
    if (v <= 0)
        return *this;
    return operator >>= ((unsigned long)v);
}


const CLASS_TYPE &
CLASS_TYPE::operator >>= (unsigned long v)
{
    if (v == 0)
        return *this;
    if (sgn == SC_ZERO)
        return *this;

    convert_SM_to_2C();

    if (sgn == SC_NEG)
        vec_shift_right(ndigits, digit, v, DIGIT_MASK);
    else
        vec_shift_right(ndigits, digit, v, 0);
    convert_2C_to_SM();
    return *this;
}


// ----------------------------------------------------------------------------
//    SECTION: EQUAL TO operator: ==
// ----------------------------------------------------------------------------

// Defined in the sc_signed.cpp and sc_unsigned.cpp.


// ----------------------------------------------------------------------------
//    SECTION: NOT_EQUAL operator: !=
// ----------------------------------------------------------------------------

bool
operator != (const CLASS_TYPE &u, const CLASS_TYPE &v)
{
    return (!operator == (u, v));
}


bool
operator != (const CLASS_TYPE &u, int64 v)
{
    return (!operator == (u, v));
}


bool
operator != (int64 u, const CLASS_TYPE &v)
{
    return (!operator == (u, v));
}


bool
operator != (const CLASS_TYPE &u, uint64 v)
{
    return (!operator == (u, v));
}


bool
operator != (uint64 u, const CLASS_TYPE &v)
{
    return (!operator == (u, v));
}


bool
operator != (const CLASS_TYPE &u, long v)
{
    return (!operator == (u, v));
}


bool
operator != (long u, const CLASS_TYPE &v)
{
    return (!operator == (u, v));
}


bool
operator != (const CLASS_TYPE &u, unsigned long v)
{
    return (!operator == (u, v));
}


bool
operator != (unsigned long u, const CLASS_TYPE &v)
{
    return (!operator == (u, v));
}


// ----------------------------------------------------------------------------
//    SECTION: LESS THAN operator: <
// ----------------------------------------------------------------------------

// Defined in the sc_signed.cpp and sc_unsigned.cpp.


// ----------------------------------------------------------------------------
//    SECTION: LESS THAN or EQUAL operator: <=
// ----------------------------------------------------------------------------

bool
operator <= (const CLASS_TYPE &u, const CLASS_TYPE &v)
{
    return (operator < (u, v) || operator == (u, v));
}


bool
operator <= (const CLASS_TYPE &u, int64 v)
{
    return (operator < (u, v) || operator == (u, v));
}


bool
operator <= (int64 u, const CLASS_TYPE &v)
{
    return (operator < (u, v) || operator == (u, v));
}


bool
operator <= (const CLASS_TYPE &u, uint64 v)
{
    return (operator < (u, v) || operator == (u, v));
}


bool
operator <= (uint64 u, const CLASS_TYPE &v)
{
    return (operator < (u, v) || operator == (u, v));
}


bool
operator <= (const CLASS_TYPE &u, long v)
{
    return (operator < (u, v) || operator == (u, v));
}


bool
operator <= (long u, const CLASS_TYPE &v)
{
    return (operator < (u, v) || operator == (u, v));
}


bool
operator <= (const CLASS_TYPE &u, unsigned long v)
{
    return (operator < (u, v) || operator == (u, v));
}


bool
operator <= (unsigned long u, const CLASS_TYPE &v)
{
    return (operator < (u, v) || operator == (u, v));
}


// ----------------------------------------------------------------------------
//    SECTION: GREATER THAN operator: >
// ----------------------------------------------------------------------------

bool
operator > (const CLASS_TYPE &u, const CLASS_TYPE &v)
{
    return (!(operator <= (u, v)));
}


bool
operator > (const CLASS_TYPE &u, int64 v)
{
    return (!(operator <= (u, v)));
}


bool
operator > (int64 u, const CLASS_TYPE &v)
{
    return (!(operator <= (u, v)));
}


bool
operator > (const CLASS_TYPE &u, uint64 v)
{
    return (!(operator <= (u, v)));
}


bool
operator > (uint64 u, const CLASS_TYPE &v)
{
    return (!(operator <= (u, v)));
}


bool
operator > (const CLASS_TYPE &u, long v)
{
    return (!(operator <= (u, v)));
}


bool
operator > (long u, const CLASS_TYPE &v)
{
    return (!(operator <= (u, v)));
}


bool
operator > (const CLASS_TYPE &u, unsigned long v)
{
    return (!(operator <= (u, v)));
}


bool
operator > (unsigned long u, const CLASS_TYPE &v)
{
    return (!(operator <= (u, v)));
}


// ----------------------------------------------------------------------------
//    SECTION: GREATER THAN or EQUAL operator: >=
// ----------------------------------------------------------------------------

bool
operator >= (const CLASS_TYPE &u, const CLASS_TYPE &v)
{
    return (!(operator < (u, v)));
}


bool
operator >= (const CLASS_TYPE &u, int64 v)
{
    return (!(operator < (u, v)));
}


bool
operator >= (int64 u, const CLASS_TYPE &v)
{
    return (!(operator < (u, v)));
}


bool
operator >= (const CLASS_TYPE &u, uint64 v)
{
    return (!(operator < (u, v)));
}


bool
operator >= (uint64 u, const CLASS_TYPE &v)
{
    return (!(operator < (u, v)));
}


bool
operator >= (const CLASS_TYPE &u, long v)
{
    return (!(operator < (u, v)));
}


bool
operator >= (long u, const CLASS_TYPE &v)
{
    return (!(operator < (u, v)));
}


bool
operator >= (const CLASS_TYPE &u, unsigned long v)
{
    return (!(operator < (u, v)));
}


bool
operator >= (unsigned long u, const CLASS_TYPE &v)
{
    return (!(operator < (u, v)));
}


// ----------------------------------------------------------------------------
//    SECTION: Public members - Other utils.
// ----------------------------------------------------------------------------

// Convert to int64, long, or int.
#define TO_INTX(RET_TYPE, UP_RET_TYPE) \
if (sgn == SC_ZERO) \
    return 0; \
int vnd = sc_min((int)DIGITS_PER_ ## UP_RET_TYPE, ndigits); \
RET_TYPE v = 0; \
while (--vnd >= 0) \
    v = (v << BITS_PER_DIGIT) + digit[vnd]; \
if (sgn == SC_NEG) \
    return -v; \
else \
    return v;


int64
CLASS_TYPE::to_int64() const
{
    TO_INTX(int64, INT64);
}


long
CLASS_TYPE::to_long() const
{
    TO_INTX(long, LONG);
}


int
CLASS_TYPE::to_int() const
{
    TO_INTX(int, INT);
}


// Convert to unsigned int64, unsigned long or unsigned
// int. to_uint64, to_ulong, and to_uint have the same body except for
// the type of v defined inside.
uint64
CLASS_TYPE::to_uint64() const
{
    if (sgn == SC_ZERO)
        return 0;

    int vnd = sc_min((int)DIGITS_PER_INT64, ndigits);

    uint64 v = 0;

    if (sgn == SC_NEG) {
#ifdef SC_MAX_NBITS
        sc_digit d[MAX_NDIGITS];
#else
        sc_digit *d = new sc_digit[ndigits];
#endif
        vec_copy(ndigits, d, digit);
        convert_SM_to_2C_trimmed(IF_SC_SIGNED, sgn, nbits, ndigits, d);
        while (--vnd >= 0)
            v = (v << BITS_PER_DIGIT) + d[vnd];
#ifndef SC_MAX_NBITS
        delete [] d;
#endif
    } else {
        while (--vnd >= 0)
            v = (v << BITS_PER_DIGIT) + digit[vnd];
    }
    return v;
}


unsigned long
CLASS_TYPE::to_ulong() const
{
    if (sgn == SC_ZERO)
        return 0;

    int vnd = sc_min((int)DIGITS_PER_LONG, ndigits);
    unsigned long v = 0;

    if (sgn == SC_NEG) {
#ifdef SC_MAX_NBITS
        sc_digit d[MAX_NDIGITS];
#else
        sc_digit *d = new sc_digit[ndigits];
#endif
        vec_copy(ndigits, d, digit);
        convert_SM_to_2C_trimmed(IF_SC_SIGNED, sgn, nbits, ndigits, d);
        while (--vnd >= 0)
            v = (v << BITS_PER_DIGIT) + d[vnd];
#ifndef SC_MAX_NBITS
        delete [] d;
#endif
    } else {
        while (--vnd >= 0)
            v = (v << BITS_PER_DIGIT) + digit[vnd];
    }
    return v;
}


unsigned int
CLASS_TYPE::to_uint() const
{
    if (sgn == SC_ZERO)
        return 0;

    int vnd = sc_min((int)DIGITS_PER_INT, ndigits);
    unsigned int v = 0;
    if (sgn == SC_NEG) {
#ifdef SC_MAX_NBITS
        sc_digit d[MAX_NDIGITS];
#else
        sc_digit *d = new sc_digit[ndigits];
#endif
        vec_copy(ndigits, d, digit);
        convert_SM_to_2C_trimmed(IF_SC_SIGNED, sgn, nbits, ndigits, d);
        while (--vnd >= 0)
            v = (v << BITS_PER_DIGIT) + d[vnd];
#ifndef SC_MAX_NBITS
        delete [] d;
#endif
    } else {
        while (--vnd >= 0)
            v = (v << BITS_PER_DIGIT) + digit[vnd];
    }
    return v;
}


// Convert to double.
double
CLASS_TYPE::to_double() const
{
    if (sgn == SC_ZERO)
        return (double) 0.0;

    int vnd = ndigits;
    double v = 0.0;
    while (--vnd >= 0)
        v = v * DIGIT_RADIX + digit[vnd];
    if (sgn == SC_NEG)
        return -v;
    else
        return v;
}


// Return true if the bit i is 1, false otherwise. If i is outside the
// bounds, return 1/0 according to the sign of the number by assuming
// that the number has infinite length.

bool
CLASS_TYPE::test(int i) const
{
#ifdef SC_SIGNED
    if (check_if_outside(i)) {
        if (sgn == SC_NEG)
            return 1;
        else
            return 0;
    }
#else
    if (check_if_outside(i))
        return 0;
#endif

    int bit_num = bit_ord(i);
    int digit_num = digit_ord(i);

    if (sgn == SC_NEG) {
#ifdef SC_MAX_NBITS
        sc_digit d[MAX_NDIGITS];
#else
        sc_digit *d = new sc_digit[ndigits];
#endif
        vec_copy(ndigits, d, digit);
        vec_complement(ndigits, d);
        bool val = ((d[digit_num] & one_and_zeros(bit_num)) != 0);
#ifndef SC_MAX_NBITS
        delete [] d;
#endif
        return val;
    } else {
        return ((digit[digit_num] & one_and_zeros(bit_num)) != 0);
    }
}


// Set the ith bit with 1.
void
CLASS_TYPE::set(int i)
{
    if (check_if_outside(i))
        return;

    int bit_num = bit_ord(i);
    int digit_num = digit_ord(i);

    convert_SM_to_2C();
    digit[digit_num] |= one_and_zeros(bit_num);
    digit[digit_num] &= DIGIT_MASK; // Needed to zero the overflow bits.
    convert_2C_to_SM();
}


// Set the ith bit with 0, i.e., clear the ith bit.
void
CLASS_TYPE::clear(int i)
{
    if (check_if_outside(i))
        return;

    int bit_num = bit_ord(i);
    int digit_num = digit_ord(i);

    convert_SM_to_2C();
    digit[digit_num] &= ~(one_and_zeros(bit_num));
    digit[digit_num] &= DIGIT_MASK; // Needed to zero the overflow bits.
    convert_2C_to_SM();
}


// Create a mirror image of the number.
void
CLASS_TYPE::reverse()
{
    convert_SM_to_2C();
    vec_reverse(length(), ndigits, digit, length() - 1);
    convert_2C_to_SM();
}


// Get a packed bit representation of the number.
void
CLASS_TYPE::get_packed_rep(sc_digit *buf) const
{
    int buf_ndigits = (length() - 1) / BITS_PER_DIGIT_TYPE + 1;
    // Initialize buf to zero.
    vec_zero(buf_ndigits, buf);

    if (sgn == SC_ZERO)
        return;

    const sc_digit *digit_or_d;
#ifdef SC_MAX_NBITS
    sc_digit d[MAX_NDIGITS];
#else
    sc_digit *d = new sc_digit[ndigits];
#endif

    if (sgn == SC_POS) {
        digit_or_d = digit;
    } else {
        // If sgn is negative, we have to convert digit to its 2's
        // complement. Since this function is const, we can not do it on
        // digit. Since buf doesn't have overflow bits, we cannot also do
        // it on buf. Thus, we have to do the complementation on a copy of
        // digit, i.e., on d.

        vec_copy(ndigits, d, digit);
        vec_complement(ndigits, d);
        buf[buf_ndigits - 1] = ~((sc_digit) 0);
        digit_or_d = d;
    }

    // Copy the bits from digit to buf. The division and mod operations
    // below can be converted to addition/subtraction and comparison
    // operations at the expense of complicating the code. We can do it
    // if we see any performance problems.

    for (int i = length() - 1; i >= 0; --i) {

        if ((digit_or_d[digit_ord(i)] &
                    one_and_zeros(bit_ord(i))) != 0) { // Test.
            buf[i / BITS_PER_DIGIT_TYPE] |=
                one_and_zeros(i % BITS_PER_DIGIT_TYPE); // Set.
        } else {
            buf[i / BITS_PER_DIGIT_TYPE] &=
                ~(one_and_zeros(i % BITS_PER_DIGIT_TYPE)); // Clear.
        }
    }

#ifndef SC_MAX_NBITS
    delete[] d;
#endif
}


// Set a packed bit representation of the number.
void
CLASS_TYPE::set_packed_rep(sc_digit *buf)
{
    // Initialize digit to zero.
    vec_zero(ndigits, digit);

    // Copy the bits from buf to digit.
    for (int i = length() - 1; i >= 0; --i) {
        if ((buf[i / BITS_PER_DIGIT_TYPE] &
                 one_and_zeros(i % BITS_PER_DIGIT_TYPE)) != 0) { // Test.
            digit[digit_ord(i)] |= one_and_zeros(bit_ord(i)); // Set.
        } else {
            digit[digit_ord(i)] &= ~(one_and_zeros(bit_ord(i))); // Clear
        }
    }
    convert_2C_to_SM();
}


// ----------------------------------------------------------------------------
//    SECTION: Private members.
// ----------------------------------------------------------------------------

// Create a copy of v with sgn s.
CLASS_TYPE::CLASS_TYPE(const CLASS_TYPE &v, small_type s) :
    sc_value_base(v), sgn(s), nbits(v.nbits), ndigits(v.ndigits), digit()
{
#ifndef SC_MAX_NBITS
    digit = new sc_digit[ndigits];
#endif
    vec_copy(ndigits, digit, v.digit);
}


// Create a copy of v where v is of the different type.
CLASS_TYPE::CLASS_TYPE(const OTHER_CLASS_TYPE &v, small_type s) :
    sc_value_base(v), sgn(s), nbits(num_bits(v.nbits)), ndigits(), digit()
{
#if (IF_SC_SIGNED == 1)
    ndigits = v.ndigits;
#else
    ndigits = DIV_CEIL(nbits);
#endif

#ifndef SC_MAX_NBITS
    digit = new sc_digit[ndigits];
#endif

    copy_digits(v.nbits, v.ndigits, v.digit);
}


// Create a signed number with (s, nb, nd, d) as its attributes (as
// defined in class CLASS_TYPE). If alloc is set, delete d.
CLASS_TYPE::CLASS_TYPE(
        small_type s, int nb, int nd, sc_digit *d, bool alloc) :
    sc_value_base(), sgn(s), nbits(num_bits(nb)), ndigits(), digit()
{
    ndigits = DIV_CEIL(nbits);
#ifndef SC_MAX_NBITS
    digit = new sc_digit[ndigits];
#endif

    if (ndigits <= nd)
        vec_copy(ndigits, digit, d);
    else
        vec_copy_and_zero(ndigits, digit, nd, d);

#ifndef SC_MAX_NBITS
    if (alloc)
        delete [] d;
#endif
}

// This constructor is mainly used in finding a "range" of bits from a
// number of type CLASS_TYPE. The function range(l, r) can have
// arbitrary precedence between l and r. If l is smaller than r, then
// the output is the reverse of range(r, l).
CLASS_TYPE::CLASS_TYPE(const CLASS_TYPE *u, int l, int r) :
        sc_value_base(), sgn(), nbits(), ndigits(), digit()
{
    bool reversed = false;

    if (l < r) {
        reversed = true;
        int tmp = l;
        l = r;
        r = tmp;
    }

    // at this point, l >= r

    // make sure that l and r point to the bits of u
    r = sc_max(r, 0);
    l = sc_min(l, u->nbits - 1);

    nbits = num_bits(l - r + 1);

    // nbits can still be <= 0 because l and r have just been updated
    // with the bounds of u.

    // if u == 0 or the range is out of bounds, return 0
    if (u->sgn == SC_ZERO || nbits <= num_bits(0)) {
        sgn = SC_ZERO;
        if (nbits <= num_bits(0)) {
            nbits = 1;
        }
        ndigits = DIV_CEIL(nbits);
#ifndef SC_MAX_NBITS
        digit = new sc_digit[ndigits];
#endif
        vec_zero(ndigits, digit);
        return;
    }

    // The rest will be executed if u is not zero.

    ndigits = DIV_CEIL(nbits);

    // The number of bits up to and including l and r, respectively.
    int nl = l + 1;
    int nr = r + 1;

    // The indices of the digits that have lth and rth bits, respectively.
    int left_digit = DIV_CEIL(nl) - 1;
    int right_digit = DIV_CEIL(nr) - 1;

    int nd;

    // The range is performed on the 2's complement representation, so
    // first get the indices for that.
    if (u->sgn == SC_NEG)
        nd = left_digit + 1;
    else
        nd = left_digit - right_digit + 1;

    // Allocate memory for the range.
#ifdef SC_MAX_NBITS
    sc_digit d[MAX_NDIGITS];
#else
    digit = new sc_digit[ndigits];
    sc_digit *d = new sc_digit[nd];
#endif

    // Getting the range on the 2's complement representation.
    if (u->sgn == SC_NEG) {
        vec_copy(nd, d, u->digit);
        vec_complement(nd, d); // d = -d;
        vec_shift_right(nd, d, r, DIGIT_MASK);
    } else {
        for (int i = right_digit; i <= left_digit; ++i)
            d[i - right_digit] = u->digit[i];
        vec_shift_right(nd, d, r - right_digit * BITS_PER_DIGIT, 0);
    }

    vec_zero(ndigits, digit);

    if (!reversed) {
        vec_copy(sc_min(nd, ndigits), digit, d);
    } else {
        // If l < r, i.e., reversed is set, reverse the bits of digit.    d
        // will be used as a temporary store. The following code tries to
        // minimize the use of bit_ord and digit_ord, which use mod and
        // div operators. Since these operators are function calls to
        // standard library routines, they are slow. The main idea in
        // reversing is "read bits out of d from left to right and push
        // them into digit using right shifting."

        // Take care of the last digit.
        int nd_less_1 = nd - 1;

        // Deletions will start from the left end and move one position
        // after each deletion.
        sc_digit del_mask = one_and_zeros(bit_ord(l - r));

        while (del_mask) {
            vec_shift_right(ndigits, digit, 1,
                    ((d[nd_less_1] & del_mask) != 0));
            del_mask >>= 1;
        }

        // Take care of the other digits if any.

        // Insertion to digit will always occur at the left end.
        sc_digit ins_mask = one_and_zeros(BITS_PER_DIGIT - 1);

        for (int j = nd - 2; j >= 0; --j) { // j = nd - 2
            // Deletions will start from the left end and move one position
            // after each deletion.
            del_mask = ins_mask;
            while (del_mask) {
                vec_shift_right(ndigits, digit, 1, ((d[j] & del_mask) != 0));
                del_mask >>= 1;
            }
        }

        if (u->sgn == SC_NEG)
            vec_shift_right(ndigits, digit,
                            ndigits * BITS_PER_DIGIT - length(), DIGIT_MASK);
        else
            vec_shift_right(ndigits, digit,
                            ndigits * BITS_PER_DIGIT - length(), 0);


    } // if reversed.

    convert_2C_to_SM();

#ifndef SC_MAX_NBITS
    delete [] d;
#endif
}

// This constructor is mainly used in finding a "range" of bits from a
// number of type OTHER_CLASS_TYPE. The function range(l, r) can have
// arbitrary precedence between l and r. If l is smaller than r, then
// the output is the reverse of range(r, l).
CLASS_TYPE::CLASS_TYPE(const OTHER_CLASS_TYPE *u, int l, int r) :
        sc_value_base(), sgn(), nbits(), ndigits(), digit()
{
    bool reversed = false;

    if (l < r) {
        reversed = true;
        int tmp = l;
        l = r;
        r = tmp;
    }

    // at this point, l >= r

    // make sure that l and r point to the bits of u
    r = sc_max(r, 0);
    l = sc_min(l, u->nbits - 1);

    nbits = num_bits(l - r + 1);

    // nbits can still be <= 0 because l and r have just been updated
    // with the bounds of u.

    // if u == 0 or the range is out of bounds, return 0
    if (u->sgn == SC_ZERO || nbits <= num_bits(0)) {
        sgn = SC_ZERO;
        if (nbits <= num_bits(0)) {
            nbits = 1;
        }
        ndigits = DIV_CEIL(nbits);
#ifndef SC_MAX_NBITS
        digit = new sc_digit[ndigits];
#endif
        vec_zero(ndigits, digit);
        return;
    }

    // The rest will be executed if u is not zero.

    ndigits = DIV_CEIL(nbits);

    // The number of bits up to and including l and r, respectively.
    int nl = l + 1;
    int nr = r + 1;

    // The indices of the digits that have lth and rth bits, respectively.
    int left_digit = DIV_CEIL(nl) - 1;
    int right_digit = DIV_CEIL(nr) - 1;

    int nd;

    // The range is performed on the 2's complement representation, so
    // first get the indices for that.
    if (u->sgn == SC_NEG)
        nd = left_digit + 1;
    else
        nd = left_digit - right_digit + 1;

    // Allocate memory for the range.
#ifdef SC_MAX_NBITS
    sc_digit d[MAX_NDIGITS];
#else
    digit = new sc_digit[ndigits];
    sc_digit *d = new sc_digit[nd];
#endif

    // Getting the range on the 2's complement representation.
    if (u->sgn == SC_NEG) {
        vec_copy(nd, d, u->digit);
        vec_complement(nd, d); // d = -d;
        vec_shift_right(nd, d, r, DIGIT_MASK);
    } else {
        for (int i = right_digit; i <= left_digit; ++i)
            d[i - right_digit] = u->digit[i];
        vec_shift_right(nd, d, r - right_digit * BITS_PER_DIGIT, 0);
    }

    vec_zero(ndigits, digit);

    if (!reversed) {
        vec_copy(sc_min(nd, ndigits), digit, d);
    } else {
        // If l < r, i.e., reversed is set, reverse the bits of digit.    d
        // will be used as a temporary store. The following code tries to
        // minimize the use of bit_ord and digit_ord, which use mod and
        // div operators. Since these operators are function calls to
        // standard library routines, they are slow. The main idea in
        // reversing is "read bits out of d from left to right and push
        // them into digit using right shifting."

        // Take care of the last digit.
        int nd_less_1 = nd - 1;

        // Deletions will start from the left end and move one position
        // after each deletion.
        sc_digit del_mask = one_and_zeros(bit_ord(l - r));

        while (del_mask) {
            vec_shift_right(ndigits, digit, 1,
                    ((d[nd_less_1] & del_mask) != 0));
            del_mask >>= 1;
        }

        // Take care of the other digits if any.

        // Insertion to digit will always occur at the left end.
        sc_digit ins_mask = one_and_zeros(BITS_PER_DIGIT - 1);

        for (int j = nd - 2; j >= 0; --j) { // j = nd - 2
            // Deletions will start from the left end and move one position
            // after each deletion.
            del_mask = ins_mask;

            while (del_mask) {
                vec_shift_right(ndigits, digit, 1, ((d[j] & del_mask) != 0));
                del_mask >>= 1;
            }
        }

        if (u->sgn == SC_NEG)
            vec_shift_right(ndigits, digit,
                            ndigits * BITS_PER_DIGIT - length(), DIGIT_MASK);
        else
            vec_shift_right(ndigits, digit,
                            ndigits * BITS_PER_DIGIT - length(), 0);


    } // if reversed.

    convert_2C_to_SM();

#ifndef SC_MAX_NBITS
    delete [] d;
#endif
}


// Print out all the physical attributes.
void
CLASS_TYPE::dump(::std::ostream &os) const
{
    // Save the current setting, and set the base to decimal.
    ::std::ios::fmtflags old_flags = 
        os.setf(::std::ios::dec, ::std::ios::basefield);

    os << "width = " << length() << ::std::endl;
    os << "value = " << *this << ::std::endl;
    os << "bits  = ";

    int len = length();

    for (int i = len - 1; i >= 0; --i) {
        os << "01"[test(i)];
        if (--len % 4 == 0)
            os << " ";
    }

    os << ::std::endl;

    // Restore old_flags.
    os.setf(old_flags, ::std::ios::basefield);
}


// Checks to see if bit_num is out of bounds.
bool
CLASS_TYPE::check_if_outside(int bit_num) const
{
    if ((bit_num < 0) || (num_bits(bit_num) >= nbits)) {
#ifdef DEBUG_SYSTEMC
        if (bit_num < 0 || bit_num >= nbits) {
                std::stringstream msg;
                msg << CLASS_TYPE_STR "::check_if_outside(int bit_num) : "
                             "bit_num = " << bit_num << " is out of bounds";
                SC_REPORT_WARNING(sc_core::SC_ID_OUT_OF_BOUNDS_,
                                  msg.str().c_str());
        }
#endif
        return true;
    }
    return false;
}