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); } } }
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)); }
// 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); } }
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(); }
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)); }
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 } }
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); }
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; }