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; }
bignum greatestCommonFactor(const bignum &bn1, const bignum &bn2) { if (bn1.isNegative() != bn2.isNegative()) return greatestCommonFactor(bn1.absolute(), bn2.absolute()); if (bn1.getDecimalCount() > 0 || bn2.getDecimalCount() > 0) throw error_handler(__FILE__, __LINE__, "Greatest common factor can only be found with two integers"); if (bn1 == bn2) return bn1; bignum lowest = bn1 < bn2 ? bn1 : bn2; bignum highest = bn1 > bn2 ? bn1 : bn2; int converted_lowest = (int)lowest; int converted_highest = (int)highest; if (highest % lowest == 0) return lowest; for (int i = converted_lowest; i > 1; i--) { if (converted_lowest % i == 0 && converted_highest % i == 0) { bignum temp(i); temp.convertBase(bn1.getBase()); return temp; } } bignum one(1); one.setBase(bn1.getBase()); return one; }
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; }
void primeFactorization(const bignum &bn, vector<bignum> &factors) { if (bn.getDecimalCount() > 0) throw error_handler(__FILE__, __LINE__, "Cannot find the prime factorization of a decimal"); //converts to base 10 first for faster prime checks, then converts base of all prime factors in the list if (bn.getBase() != 10) { bignum converted(bn); converted.convertBase(10); primeFactorization(converted, factors); for (vector<bignum>::iterator i = factors.begin(); i != factors.end(); i++) i->convertBase(bn.getBase()); return; } if (bn < 0) { factors.push_back(-1); if (bn.absolute().isPrime()) { factors.push_back(bn.absolute()); return; } else return primeFactorization(bn.absolute(), factors); } if (bn.isPrime()) { factors.push_back(1); factors.push_back(bn); return; } bignum temp(2); while (bn % temp != 0) temp++; if (!(bn / temp).isPrime()) primeFactorization(bn / temp, factors); else factors.push_back(bn / temp); if (!temp.isPrime()) primeFactorization(temp, factors); else factors.push_back(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; }
bignum fibonacci(const bignum &b) { if (b.getDecimalCount() > 0) throw error_handler(__FILE__, __LINE__, "fibonacci sequence values may only be derived from integers"); bignum counter; bignum high; bignum low; bignum temp; bignum zero; counter.setBase(b.getBase()); high.setBase(b.getBase()); low.setBase(b.getBase()); if (b > bignum(bignum(), b.getBase())) { high++; while (counter < b) { temp = low; low = high; high += temp; counter++; } return low; } else if (b < bignum(bignum(), b.getBase())) { low++; while (counter > b.absolute()) { temp = high; high = low; low = (temp - low); counter++; } return high; } return temp; }
//returns random number within range with a specified resolution bignum randomNumberForcePrecision(const bignum &bn1, const bignum &bn2, int force_precision) { if (bn1.getBase() != bn2.getBase()) throw error_handler(__FILE__, __LINE__, "random numbers can only be generated between numbers of the same base"); if (bn1 == bn2) return bn1; bignum difference; difference.setBase(bn1.getBase()); difference = (bn1 > bn2 ? bn1 - bn2 : bn2 - bn1); int start = difference.getDigitCount() - 1; int tempdigit; int counter = difference.getDigitRange(); //increment is a random bignum between 0 and the difference of the two bignum increment; increment.setBase(difference.getBase()); //verifies that random digit selected for particular index won't make the random number greater than the difference bool increment_is_lower_than_difference = false; for (int i = 0; i < counter; i++) { int index = (start - i); if (index < 0 || index < force_precision) break; if (increment_is_lower_than_difference) tempdigit = (rand() % difference.getBase()); else { tempdigit = (rand() % difference.getDigit(index) + 1); increment_is_lower_than_difference = tempdigit < difference.getDigit(index); } increment.setDigit(index, tempdigit); } increment.setDigit((difference.getDigitCount() - counter), 1); return (bn1 < bn2 ? bn1 + increment : bn2 + increment); }
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; }
//returns random number within range with added resolution bignum randomNumberAddPrecision(const bignum &bn1, const bignum &bn2, int add_precision) { if (bn1.getBase() != bn2.getBase()) throw error_handler(__FILE__, __LINE__, "random numbers can only be generated between numbers of the same base"); if (bn1 == bn2) return bn1; bignum difference; difference.setBase(bn1.getBase()); difference = (bn1 > bn2 ? bn1 - bn2 : bn2 - bn1); int start = difference.getDigitCount() - 1; int new_right_most = (add_precision > 0 ? difference.getRightMost() - add_precision : difference.getRightMost()); //increment is a random bignum between 0 and the difference of the two bignum increment; increment.setBase(difference.getBase()); int tempdigit; bignum mod; mod.setBase(difference.getBase()); //verifies that random digit selected for particular index won't make the random number greater than the difference bool increment_is_lower_than_difference = false; for (int i = start; i >= new_right_most; i--) { if (i < 0) break; tempdigit = (rand() % difference.getBase()); mod.setDigit(i, tempdigit); } increment = modulo(mod, difference); return (bn1 < bn2 ? bn1 + increment : bn2 + increment); }
bignum divideNumbersSimple(const bignum &bn1, const bignum &bn2, bool &remainder) { bignum temp(bn1); bignum counter; counter.setBase(bn1.getBase()); while (temp >= bn2) { temp -= bn2; counter++; } //adjusts bool passed for remainder if ((counter * bn2) == temp) remainder = false; else remainder = true; return counter; }
bignum multiplyNumbersSimple(const bignum &bn1, int n) { if (n == 0) { bignum zero; zero.setBase(bn1.getBase()); return zero; } bignum temp(bn1); //if both numbers are negative, make the result positive if (bn1.isNegative() == n < 0) temp.setPositive(); //add the first number to itself n times for (int i = 0; i < (n - 1); i++) temp += bn1; 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; } } }