bool greaterThan(const bignum &bn1, const bignum &bn2) { //if bases are different, convert the second and re-evaluate if (bn1.getBase() != bn2.getBase()) return greaterThan(bn1, bn2.getConverted(bn1.getBase())); if (bn1 == bn2) return false; if (bn1.isNegative() && !bn2.isNegative()) return false; if (!bn1.isNegative() && bn2.isNegative()) return true; if (bn1.isNegative() && bn2.isNegative()) return (lessThan(bn1.absolute(), bn2.absolute())); if (bn1.getDigitCount() > bn2.getDigitCount()) return true; if (bn1.getDigitCount() < bn2.getDigitCount()) return false; for (int i = bn1.getDigitCount() - 1; i >= 0; i--) { if (bn1.getDigit(i) > bn2.getDigit(i)) return true; if (bn1.getDigit(i) < bn2.getDigit(i)) return false; } return false; }
bool lessThan(const bignum &bn1, const bignum &bn2) { if (bn1.getBase() != bn2.getBase()) return lessThan(bn1, bn2.getConverted(bn1.getBase())); if (bn1 == bn2) return false; if (bn1.isNegative() && !bn2.isNegative()) return true; if (!bn1.isNegative() && bn2.isNegative()) return false; if (bn1.isNegative() && bn2.isNegative()) return (greaterThan(bn1.absolute(), bn2.absolute())); if (bn1.getDigitCount() < bn2.getDigitCount()) return true; if (bn1.getDigitCount() > bn2.getDigitCount()) return false; for (int i = bn1.getDigitCount() - 1; i >= 0; i--) { if (bn1.getDigit(i) < bn2.getDigit(i)) return true; if (bn1.getDigit(i) > bn2.getDigit(i)) return false; } return false; }
bignum exponent(const bignum &base_value, const bignum &power, int precision) { if (base_value.getBase() != power.getBase()) return exponent(base_value, power.getConverted(power.getBase())); bignum one(1); one.setBase(base_value.getBase()); one.setPositive(); if (power.isZero()) return one; //if the power is negative, return 1/solution if (power.isNegative()) return one / exponent(base_value, power.absolute()); if (power.getDecimalCount() > 0) { if (power < 1) { bignum modified_power(power); modified_power.leftShift(power.getDecimalCount()); bignum divisor(1); divisor.setBase(power.getBase()); divisor.leftShift(power.getDecimalCount()); bignum gcf(greatestCommonFactor(modified_power, divisor)); modified_power /= gcf; divisor /= gcf; bignum divisor_root_of_base = jep::root(divisor, base_value, precision); return exponent(divisor_root_of_base, modified_power).getRoundedAllDigits(ONES_PLACE - precision); } else { bignum power_decimal = power % 1; bignum power_int = power.getRoundedDown(ONES_PLACE); return exponent(base_value, power_int, precision) * exponent(base_value, power_decimal, precision); } } bignum counter = power.absolute(); bignum temp(base_value); //n^0 always returns 1 if (power.isZero()) return one; while (counter > one) { temp *= base_value; counter--; } return temp; }
bignum combinations(const bignum &bn1, const bignum &bn2) { if (bn1.getBase() != bn2.getBase()) return combinations(bn1, bn2.getConverted(bn1.getBase())); bignum first = factorial(bn1); bignum second = bn1 - bn2; bignum third = factorial(second); bignum fourth = factorial(bn2); bignum fifth = third * fourth; bignum temp = divideNumbers(first, fifth); return temp; }
bool equals(const bignum &bn1, const bignum &bn2) { if (bn1.getBase() != bn2.getBase()) return equals(bn1, bn2.getConverted(bn1.getBase())); if (bn1.isNegative() != bn2.isNegative()) return false; if (bn1.getDigitCount() != bn2.getDigitCount()) return false; if (bn1.getDecimalCount() != bn2.getDecimalCount()) return false; for (int i = bn1.getDigitCount(); i > 0; i--) { if (bn1.getDigit(i - 1) != bn2.getDigit(i - 1)) return false; } return true; }
bignum multiplyNumbers(const bignum &bn1, const bignum &bn2) { if (bn1.getBase() != bn2.getBase()) return multiplyNumbers(bn1, bn2.getConverted(bn1.getBase())); bignum temp(0); temp.setBase(bn1.getBase()); if (bn1.isZero() || bn2.isZero()) return temp; //multiply bn1 by each digit of bn2 independently, then add the values together int counter = bn2.getDigitRange(); for (int i = 0; i < counter; i++) { int toMultiply = (ONES_PLACE - bn2.getDecimalCount()) + i; //verify function isn't checking beyond bounds of the stored array if (toMultiply >= 0) { if (toMultiply >= MAXDIGITS) throw error_handler(__FILE__, __LINE__, "The value being calculated is too large for the settings provided"); bignum toAdd = multiplyNumbersSimple(bn1.absolute(), bn2.getDigit(toMultiply)); toAdd.leftShift(i); temp += toAdd; } } if (bn1.isNegative() != bn2.isNegative()) temp.setNegative(); //adjust for added decimal places during multiplication temp.rightShift(bn2.getDecimalCount()); temp.updateDigits(); return temp; }
bignum divideNumbers(const bignum &bn1, const bignum &bn2) { if (bn2.isZero()) throw error_handler(__FILE__, __LINE__, "Cannot divide a number by zero"); bignum temp; bool negative_result = (bn1.isNegative() != bn2.isNegative()); if (bn1.getBase() != bn2.getBase()) return divideNumbers(bn1, bn2.getConverted(bn1.getBase())); //set base of the return value to match that of the passed values int baseSet = bn1.getBase(); temp.setBase(baseSet); bool remainder = false; bool end = false; int index = bn1.getDigitCount() - 1; //starting with the left-most digit, create a bignumber of that digit that matches the set base bignum number_to_compare(bn1.getDigit(index)); number_to_compare.convertBase(baseSet); //ignore decimal places when comparing dividend to digits of the divisor bignum nextNumber = divideNumbersSimple(number_to_compare, bn2.absolute().noDecimal(), remainder); bignum number_to_subtract; number_to_subtract.setBase(baseSet); while (!end && index >= 0) { if (index >= MAXDIGITS) throw error_handler(__FILE__, __LINE__, "The value being calculated is too large for the settings provided"); if (remainder == false && index < ONES_PLACE - bn1.getDecimalCount()) end = true; temp.setDigit(index, nextNumber.getDigit(ONES_PLACE)); index--; number_to_subtract = bn2.absolute().noDecimal() * nextNumber; number_to_subtract.updateDigits(); number_to_compare -= number_to_subtract; number_to_compare.leftShift(1); if (index >= 0) { bignum digit(bn1.getDigit(index)); digit.convertBaseSimple(number_to_compare.getBase()); number_to_compare += digit; } nextNumber = divideNumbersSimple(number_to_compare, bn2.absolute().noDecimal(), remainder); if (index < 0) end = true; } if (negative_result && temp != 0) temp.setNegative(); temp.leftShift(bn2.getDecimalCount()); return temp; }
bignum subtractNumbers(const bignum &bn1, const bignum &bn2) { if (bn1.getBase() != bn2.getBase()) return subtractNumbers(bn1, bn2.getConverted(bn1.getBase())); int base = bn1.getBase(); bignum difference; difference.setBase(base); //evaluate the numbers being of equal absolute value if (bn1.absolute() == bn2.absolute()) { // -12 - 12 ---> -(12 + 12) if (bn1.isNegative() && !bn2.isNegative()) { bignum temp = addNumbers(bn1.absolute(), bn2.absolute()); temp.setNegative(); temp.updateDigits(); return temp; } // 12 - -12 ---> 12 + 12 if (!bn1.isNegative() && bn2.isNegative()) return addNumbers(bn1.absolute(), bn2.absolute()); // -12 - -12 ---> 0 if (bn1.isNegative() && bn2.isNegative()) { bignum temp; temp.setBase(base); return temp; } } //evaluate the numbers if absolute first is larger than absolute second if (bn1.absolute() > bn2.absolute()) { // -12 - 8 ---> -(12 + 8) if (bn1.isNegative() && !bn2.isNegative()) { bignum temp = addNumbers(bn1.absolute(), bn2.absolute()); temp.setNegative(); temp.updateDigits(); return temp; } // 12 - -8 ---> 12 + 8 if (!bn1.isNegative()&& bn2.isNegative()) return addNumbers(bn1.absolute(), bn2.absolute()); // -12 - -8 ---> -(12 - 8) if (bn1.isNegative() && bn2.isNegative()) { bignum temp = subtractNumbers(bn1.absolute(), bn2.absolute()); temp.setNegative(); temp.updateDigits(); return temp; } } //evaluate the numbers if absolute first is smaller than absolute second if (bn1.absolute() < bn2.absolute()) { // 8 - 12 ---> -(12 - 8) if (!bn1.isNegative()&& !bn2.isNegative()) { bignum temp = subtractNumbers(bn2.absolute(), bn1.absolute()); temp.setNegative(); temp.updateDigits(); return temp; } // -8 - 12 ---> -(8 + 12) if (bn1.isNegative() && !bn2.isNegative()) { bignum temp = addNumbers(bn1.absolute(), bn2.absolute()); temp.setNegative(); temp.updateDigits(); return temp; } // 8 - -12 ---> 8 + 12 if (!bn1.isNegative() && bn2.isNegative()) return addNumbers(bn1.absolute(), bn2.absolute()); // -8 - -12 ---> (12 - 8) if (bn1.isNegative() && bn2.isNegative()) return subtractNumbers(bn2.absolute(), bn1.absolute()); } int carry = 0; int digits = 0; int decimal = 0; //bool carry_negative = false; //sets decimal and digit values to the highest of each number decimal = (bn1.getDecimalCount() > bn2.getDecimalCount() ? bn1.getDecimalCount() : bn2.getDecimalCount()); digits = (bn1.getDigitCount() > bn2.getDigitCount() ? bn1.getDigitCount() + 1 : bn2.getDigitCount() + 1); for (int i = (ONES_PLACE - decimal); i < digits + 1 && i >= 0; i++) { if (i >= MAXDIGITS) throw error_handler(__FILE__, __LINE__, "The value being calculated is too large for the settings provided"); int tempNumber = bn1.getDigit(i) - bn2.getDigit(i); tempNumber -= carry; if (tempNumber < 0) { tempNumber += base; carry = 1; } else carry = 0; difference.setDigit(i, tempNumber); } difference.updateDigits(); difference.setBase(base); return difference; }
bignum addNumbers(const bignum &bn1, const bignum &bn2) { if (bn1.getBase() != bn2.getBase()) return addNumbers(bn1, bn2.getConverted(bn1.getBase())); if (bn1.absolute() == bn2.absolute()) { // -12 + 12 or 12 + -12 ---> 0 if (bn1.isNegative() != bn2.isNegative()) { bignum temp; temp.setBase(bn1.getBase()); return temp; } // -12 + -12 ---> -(12 + 12) if (bn1.isNegative() && bn2.isNegative()) { bignum temp(addNumbers(bn1.absolute(), bn2.absolute())); temp.setNegative(); temp.updateDigits(); return temp; } } if (bn1.absolute() > bn2.absolute()) { // -12 + 8 ---> -(12 - 8) if (bn1.isNegative() && !bn2.isNegative()) { bignum temp = subtractNumbers(bn1.absolute(), bn2.absolute()); temp.setNegative(); temp.updateDigits(); return temp; } // 12 + -8 ---> 12 - 8 if (!bn1.isNegative() && bn2.isNegative()) return subtractNumbers(bn1.absolute(), bn2.absolute()); // -12 + -8 ---> -(12 + 8) if (bn1.isNegative()&& bn2.isNegative()) { bignum temp = addNumbers(bn1.absolute(), bn2.absolute()); temp.setNegative(); temp.updateDigits(); return temp; } } if (bn1.absolute() < bn2.absolute()) { // -8 + 12 ---> 12 - 8 if (bn1.isNegative() && !bn2.isNegative()) { bignum temp = subtractNumbers(bn2.absolute(), bn1.absolute()); temp.updateDigits(); return temp; } // 8 + -12 ---> 8 - 12 if (!bn1.isNegative() && bn2.isNegative()) return subtractNumbers(bn1.absolute(), bn2.absolute()); // -8 + -12 ---> -(8 + 12) if (bn1.isNegative() && bn2.isNegative()) { bignum temp = addNumbers(bn1.absolute(), bn2.absolute()); temp.setNegative(); temp.updateDigits(); return temp; } } int carry = 0; int digits = 0; int decimal = 0; //sets decimal and digit values to the highest of each number decimal = (bn1.getDecimalCount() > bn2.getDecimalCount() ? bn1.getDecimalCount() : bn2.getDecimalCount()); digits = (bn1.getDigitCount() > bn2.getDigitCount() ? bn1.getDigitCount() + 1 : bn2.getDigitCount() + 1); bignum sum; int base = bn1.getBase(); for (int i = (ONES_PLACE - decimal); i < digits + 1 ; i++) { if (i >= MAXDIGITS) throw error_handler(__FILE__, __LINE__, "The value being calculated is too large for the settings provided"); int tempNumber = bn1.getDigit(i) + bn2.getDigit(i); tempNumber += carry; if (tempNumber>(base - 1)) { tempNumber -= base; carry = 1; } else carry = 0; sum.setDigit(i, tempNumber); } sum.updateDigits(); sum.setBase(base); return sum; }
bignum root(const bignum &nth_root, const bignum &base_number, int decimal_places) { //std::cout << "root calc" << std::endl; if (nth_root.getBase() != base_number.getBase()) return root(nth_root, base_number.getConverted(nth_root.getBase()), decimal_places); //TODO: verify that the 2.5th root of -2 is irrational, if (base_number.isNegative()) { if (nth_root.getDecimalCount() > 0 || nth_root % 2 == 0) throw error_handler(__FILE__, __LINE__, "The program attempted to compute an irrational value"); else return root(nth_root, base_number.absolute(), decimal_places) * -1; } if (nth_root.isNegative()) { bignum one(1); one.setBase(base_number.getBase()); return root(nth_root.absolute(), one / base_number, decimal_places); } if (base_number == 0 || base_number == 1) return base_number; //cross-checks the root being tested to the precision threshold specified bignum precision_check(1); precision_check.setBase(nth_root.getBase()); precision_check.rightShift(decimal_places); bignum range_low = base_number - precision_check; bignum range_high = base_number + precision_check; bignum root_test; root_test = base_number < 1 ? base_number * nth_root : base_number / nth_root; //TODO: refine increment function to scale depending on the size of the number being tested bignum increment(1); increment.setBase(nth_root.getBase()); if (base_number < 1) increment.rightShift(1); bignum answer_check; answer_check.setBase(nth_root.getBase()); //sets once function finds general region of the answer bool approximate = false; for (;;) { //adjusts number precision to check for nearest round roots //prevents function from returning 3.99999 instead of 4 if (!approximate) root_test.roundToIndex(ONES_PLACE - increment.getDecimalCount()); answer_check = exponent(root_test, nth_root); if (answer_check > range_low && answer_check < range_high) return root_test; if (answer_check > base_number) { if (approximate) { root_test -= increment; increment.rightShift(1); root_test += increment; } else root_test /= nth_root; } else if (answer_check < base_number) { if (!approximate) approximate = true; root_test += increment; } } }