コード例 #1
0
ファイル: LongNumber.cpp プロジェクト: happanda/large_numbers
LongNumber LongNumber::operator -(LongNumber const& other) const
{
    if (container.isStatic() && other.container.isStatic())
    {
        // both numbers are inside long long type
        long long val1 = container.getValue() * (container.hasSign() ? -1 : 1);
        long long val2 = other.container.getValue() * (other.container.hasSign() ? -1 : 1);
        if (checkAdd(val1, -val2, val1))
            return LongNumber(NumberContainer(val1));
    }

    if (container.hasSign() ^ other.container.hasSign())
        // different signs, just add them,
        // use sign of left operand
        return LongNumber(add(container, other.container));
    else
    {
        // same sign, below |X| >= |y|
        int comp = compareAbs(container, other.container);
        if (comp >= 0)
            // X - y, us sign of X
            return LongNumber(sub(container, other.container));
        else
        {
            // y - X, use opposite to sign of X
            NumberContainer numCont = sub(other.container, container);
            numCont.setSign(!other.container.hasSign());
            return LongNumber(numCont);
        }
    }
}
コード例 #2
0
ファイル: LongNumber.cpp プロジェクト: happanda/large_numbers
LongNumber LongNumber::operator +(LongNumber const& other) const
{
    if (container.isStatic() && other.container.isStatic())
    {
        // both numbers are inside long long type
        long long val1 = container.getValue() * (container.hasSign() ? -1 : 1);
        long long val2 = other.container.getValue() * (other.container.hasSign() ? -1 : 1);
        if (checkAdd(val1, val2, val1))
            return LongNumber(NumberContainer(val1));
    }

    if (container.hasSign() ^ other.container.hasSign())
    {
        // different signs, substract min abs from greater by abs
        // use sign of greater by abs
        int comp = compareAbs(container, other.container);
        if (comp >= 0)
            return LongNumber(sub(container, other.container));
        else
            return LongNumber(sub(other.container, container));
    }
    else
        // same signs, just add them
        return LongNumber(add(container, other.container));
}
コード例 #3
0
// Linear quot. Assume x != 0 and y != 0 and f != 0
BigReal BigReal::quotLinear128(const BigReal &x, const BigReal &y, const BigReal &f, DigitPool *pool) { // static
  const bool yNegative = y.isNegative();
  ((BigReal&)y).setPositive(); // cheating. We set it back agin

  const BigReal v = APCprod(<, APCprod(<, f, Q128C.c1, pool), y, pool); // v > 0

  BigReal z(pool);
  copy(z, x, v*Q128C.c2);

  z.setPositive();

  BigReal u(pool);
  u.approxQuot32(z, v);
  u.approxQuot32(v, getExpo10N(u)*Q128C.c3 + Q128C.c4);

  BRExpoType scale;
  _uint128 yFirst;
  y.getFirst128(yFirst, MAXDIGITS_DIVISOR128, &scale);

  BigReal result(pool), t(pool), tmp(pool);
  bool loopDone = false;
  for(; compareAbs(z,v) > 0; loopDone = true) {
    t.approxQuot128Abs(z, yFirst, scale).m_negative = z.m_negative;
    result += t;
    z -= product(tmp, t, y, u, 0);
  }

  ((BigReal&)y).m_negative = yNegative;

  if(loopDone) {
    return result.setSignByProductRule(x,y);
  } else {
    return result.approxQuot128Abs(x, yFirst, scale).setSignByProductRule(x,y);
  }
}
コード例 #4
0
Double80 getDouble80(const BigReal &x) {
  DEFINEMETHODNAME;

  if(!isnormal(x)) {
    if(x.isZero()) {
      return Double80::zero;
    } else if(isnan(x)) {
      return DBL80_NAN;
    } else if(isPInfinity(x)) {
      return DBL80_PINF;
    } else {
      return DBL80_NINF;
    }
  }
  if(compareAbs(x,ConstBigReal::_dbl80_max) > 0) {
    throwBigRealGetIntegralTypeOverflowException(method, x, toString(ConstBigReal::_dbl80_max));
  }
  if(compareAbs(x,ConstBigReal::_dbl80_min) < 0) {
    throwBigRealGetIntegralTypeUnderflowException(method, x, toString(ConstBigReal::_dbl80_min));
  }
  return x.getDouble80NoLimitCheck();
}
コード例 #5
0
BigReal rExp(const BigReal &x, size_t digits) {
  DEFINEMETHODNAME;
  DigitPool *pool = x.getDigitPool();
  const BigReal c = x.isNegative() ? -rProd(REXPC.c1,fabs(x),20, pool) : rProd(REXPC.c2,x,20,pool);
  double cd;
  if(compareAbs(x, pool->getHalf()) < 0) { // prevent underflow in getDouble
    cd = 0;
  } else {
    cd = getDouble(c);
    if(cd > CD_MAX) {
      throwBigRealInvalidArgumentException(method, _T("Argument too big"));
    } else if(cd < CD_MIN) {
      throwBigRealInvalidArgumentException(method, _T("Argument too small"));
    }
  }
  return exp(x, e(_1, (intptr_t)cd - digits - 1));
}
コード例 #6
0
void quotRemainder(const BigReal &x,  const BigReal &y, BigInt *quotient, BigReal *remainder) {
  DEFINEMETHODNAME;
  if(y.isZero()) {
    throwBigRealInvalidArgumentException(method, _T("Division by zero. (%s / 0)."), x.toString().cstr());
  }
  if(quotient == remainder) { // also takes care of the stupid situation where both are NULL
    throwBigRealInvalidArgumentException(method, _T("quotient is the same variable as remainder"));
  }
  if(quotient == &x || quotient == &y) {
    throwBigRealInvalidArgumentException(method, _T("quotient cannot be the same variable as x or y"));
  }
  if(remainder == &x || remainder == &y) {
    throwBigRealInvalidArgumentException(method, _T("remainder cannot be the same variable as x or y"));
  }

  if(x.isZero()) {
    if(quotient ) quotient->setToZero();
    if(remainder) remainder->setToZero();
    return;
  }

  DigitPool *pool = x.getDigitPool();
  const int cmpAbs = compareAbs(x, y);
  if(cmpAbs < 0) {
    if(remainder) *remainder = x;
    if(quotient)  quotient->setToZero();
    return;
  } else if(cmpAbs == 0) {
    if(remainder) remainder->setToZero();
    if(quotient) {
      *quotient = quotient->getDigitPool()->get1();
    }
    return;
  }

  BigReal tmpX(x);
  tmpX.setPositive();
  BigReal tmpY(y);
  tmpY.setPositive();
  BigInt q   = floor(quot(tmpX, tmpY, modulusC1));
  BigReal mod = tmpX - q * tmpY;

  if(mod.isNegative()) {
    if(remainder) {
      *remainder = mod + tmpY;
    }
    if(quotient) {
      --q;
      *quotient = q;
    }
  } else if(mod >= tmpY) {
    if(remainder) {
      *remainder = mod - tmpY;
    }
    if(quotient) {
      ++q;
      *quotient = q;
    }
  } else {
    if(remainder) {
      *remainder = mod;
    }
    if(quotient) {
      *quotient = q;
    }
  }

  if(remainder && (remainder->m_negative != x.m_negative)) {
    remainder->m_negative = x.m_negative; // sign(x % y) = sign(x), equivalent to build-in % operator
  }
}
コード例 #7
0
ファイル: LongNumber.cpp プロジェクト: happanda/large_numbers
LongNumber LongNumber::operator /(LongNumber const& other) const
{
    if (other == LongNumber("0"))
        throw ArithmeticException("Division by zero");
    bool const needSign = container.hasSign() ^ other.container.hasSign();
    if (container.isStatic() && other.container.isStatic())
    {
        // both numbers are inside long long type, division always inside type
        long long val = container.getValue() / other.container.getValue();
        val *= needSign ? -1 : 1;
        return LongNumber(NumberContainer(val));
    }
    int const comp = compareAbs(container, other.container);
    if (comp < 0)
        return LongNumber(NumberContainer(0));
    else if (comp == 0)
    {
        NumberContainer num(1);
        num.setSign(needSign);
        return LongNumber(num);
    }
    // we have to divide here
    int const thisLen = container.length();
    int const otherLen = other.container.length();
    // use upper bound of length
    int const numLen = thisLen - otherLen + 1;
    int pos = numLen;
    NumberContainer num(false, pos--);
    num.setSign(needSign);
    NumberContainer tmp(container);// create copy

    // find where first to place other
    int from = thisLen - 1;
    for (int k1 = 0; k1 < otherLen; k1++)
    {
        int k2 = otherLen - 1 - k1;
        char dig = tmp.getDigit(from - k1);
        char odig = other.getDigit(k2);
        if (dig < odig)
        {
            from--;
            break;
        }
        if (dig > odig)
            break;
    }

    for (; from >= otherLen - 1; from--)
    {
        bool found = false;
        char curDigit = 10;
        // pick digit in answer
        while (!found && curDigit > 0)
        {
            curDigit--;
            found = true;
            int borrowed = 0;
            if (from < thisLen - 1)
                borrowed = tmp.getDigit(from + 1);
            for (int k2 = otherLen - 1; k2 >= 0 && found; k2--)
            {
                int k1 = otherLen - 1 - k2;
                char dig = tmp.getDigit(from - k1);
                char subt = curDigit * other.getDigit(k2);
                borrowed -= subt / 10;
                if (borrowed < 0 || dig + borrowed * 10 - (subt % 10) < 0)
                    found = false;
                borrowed = dig + borrowed * 10 - (subt % 10);
                if (borrowed > 99)
                    // subtracting from our dividend at current position
                    // we got mass left in higer digits, than where we are currently
                    // so we can subtract
                    break;
            }
        }
        // set digit in answer
        num.setDigit(pos--, curDigit);
        if (curDigit > 0)
        {
            // subtract from dividend
            char borrowed = 0;
            char transfered = 0;
            for (int k2 = 0; k2 < otherLen && found; k2++)
            {
                int k1 = otherLen - 1 - k2;
                char dig = tmp.getDigit(from - k1) + borrowed;
                char subt = curDigit * other.getDigit(k2) + transfered;
                transfered = subt / 10;
                subt %= 10;
                if (dig < 0)
                    tmp.setDigit(from - k1, 9 - subt);
                else if (dig >= subt)
                {
                    borrowed = 0;
                    tmp.setDigit(from - k1, dig - subt);
                }
                else
                {
                    borrowed = -1;
                    tmp.setDigit(from - k1, 10 + dig - subt);
                }
            }
        }
    }
    if (pos < 0)
        return LongNumber(num);
    // need to resize (remove first zero digit)
    NumberContainer resized(false, numLen - pos - 1);
    resized.setSign(needSign);
    for (int i = pos + 1; i < numLen; i++)
        resized.setDigit(i - pos - 1, num.getDigit(i));
    return LongNumber(resized);
}
コード例 #8
0
void quotRemainder128(const BigReal &x, const BigReal &y, BigInt *quotient, BigReal *remainder) {
  DEFINEMETHODNAME;
  if(y.isZero()) {
    throwBigRealInvalidArgumentException(method, _T("Division by zero"));
  }
  if(quotient == remainder) { // also takes care of the stupid situation where both are NULL
    throwBigRealInvalidArgumentException(method, _T("quotient is the same variable as remainder"));
  }
  if(quotient == &x || quotient == &y) {
    throwBigRealInvalidArgumentException(method, _T("quotient cannot be the same variable as x or y"));
  }
  if(remainder == &x || remainder == &y) {
    throwBigRealInvalidArgumentException(method, _T("remainder cannot be the same variable as x or y"));
  }

  if(x.isZero()) {
    if(quotient ) quotient->setToZero();
    if(remainder) remainder->setToZero();
    return;
  }

  const int cmpAbs = compareAbs(x, y);
  if(cmpAbs < 0) {
    if(remainder) *remainder = x;
    if(quotient)  quotient->setToZero();
    return;
  } else if(cmpAbs == 0) {
    if(remainder) remainder->setToZero();
    if(quotient) {
      *quotient = quotient->getDigitPool()->get1();
    }
    return;
  }

  // x != 0 && y != 0 && |x| > |y|

  if(BigReal::isPow10(y)) {
    BigReal tmp(x);
    const BRExpoType yp10 = BigReal::getExpo10(y);
    tmp.multPow10(-yp10);
    tmp.fractionate(quotient, remainder);
    if(remainder) {
      remainder->multPow10(yp10);
    }
    if(quotient) {
      quotient->setPositive();
    }
    return;
  }

  const bool yNegative = y.isNegative();
  ((BigReal&)y).setPositive(); // cheating. We set it back agin

  DigitPool *pool = x.getDigitPool();

  BigReal z(x, pool);
  z.setPositive();

  BRExpoType             scale;
  _uint128               yFirst;
  y.getFirst128(yFirst, MAXDIGITS_DIVISOR128, &scale);
  const int              yDigits      = BigReal::getDecimalDigitCount64(yFirst);

  BigReal q(pool), t(pool), tmp(pool);
  while(compareAbs(z, y) >= 0) {
    t.approxQuot128Abs(z, yFirst, scale).m_negative = z.m_negative;
    q += t;
    z -= BigReal::product(tmp, t, y, pool->get0(),0);
  }

  if(!z.isNegative()) {
    if(isInteger(q)) {
      if(quotient)  *quotient  = q;
      if(remainder) *remainder = z;
    } else {
      q.fractionate(quotient, &t);
      z += t * y;
      if(compareAbs(z, y) >= 0) {
        if(quotient)  ++(*quotient);
        if(remainder) *remainder = z - y;
      } else {
        if(remainder) *remainder = z;
      }
    }
  } else { // z < 0
    if(isInteger(q)) {
      if(quotient)  {
        *quotient = q;
        --(*quotient);
      }
      if(remainder) {
        *remainder = z + y;
      }
    } else {
      if(!remainder) { // quotient != NULL
        q.fractionate(quotient, &t);
        z += t * y;
        if(z.isNegative()) {
          --(*quotient);
        }
      } else { // remainder != NULL. quotient might be NULL
        q.fractionate(quotient, &t);
        *remainder = z + t * y;
        if(remainder->isNegative()) {
          *remainder += y;
          if(quotient) {
            --(*quotient);
          }
        }
      }
    }
  }

  if(remainder) {
    remainder->m_negative = x.m_negative;
  }
  ((BigReal&)y).m_negative = yNegative;
}