diff --git a/ci_cd/.gitlab-ci.yml b/ci_cd/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..23b3cea52b48e5646e604e2bbed2d6e84e1323fa --- /dev/null +++ b/ci_cd/.gitlab-ci.yml @@ -0,0 +1,10 @@ +stages: + - prebuild + - compile + - test + +include: + - local: 'ci_cd/problem3.yml' # FullInteger + +default: + timeout: 5m diff --git a/ci_cd/problem3.yml b/ci_cd/problem3.yml new file mode 100644 index 0000000000000000000000000000000000000000..14067bed5338adf8eab6dec13bf10bfa4308297b --- /dev/null +++ b/ci_cd/problem3.yml @@ -0,0 +1,49 @@ +prebuild_problem_3: + stage: prebuild + script: + - | + # Check if source files exist + if [ ! -f "FullInteger.cpp" ]; then + echo "FullInteger.cpp does not exist"; + exit 1; + fi + - git clone https://agile.bu.edu/gitlab/configs/ec330/homeworks/homeworkthree.git hw3 + artifacts: + paths: + - hw3/ + rules: + - if: '$CI_COMMIT_REF_NAME == "problem3"' + tags: [c++-17] + +compile_problem_3: + stage: compile + needs: + - job: prebuild_problem_3 + artifacts: true + script: + - ls -l hw3/tests/ + - cp FullInteger.cpp hw3/tests/ + - cd hw3/tests + - make problem3 + artifacts: + paths: + - hw3/ + rules: + - if: '$CI_COMMIT_REF_NAME == "problem3"' + tags: [c++-17] + +exec_problem_3: + stage: test + needs: + - job: compile_problem_3 + artifacts: true + script: + - cd hw3/tests + - ./problem3 + artifacts: + paths: + - hw3/ + rules: + - if: '$CI_COMMIT_REF_NAME == "problem3"' + tags: [c++-17] + diff --git a/tests/BigNum.cpp b/tests/BigNum.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e251d51cdbe3428838d61f1740b035099635c4e6 --- /dev/null +++ b/tests/BigNum.cpp @@ -0,0 +1,191 @@ +// +// Created by Ari Trachtenberg on 1/30/17. +// + +#include +#include +#include "../include/BigNum.h" + +// IMPLEMENTATION + +BigNum::BigNum(const string &num) { + bool leading = true; // used to ignore leading zeroes + for (int ii = 0; ii < num.length(); ii++) + if (leading && num[ii] == '0') + continue; + else { + leading = false; + digits.insert(digits.begin(), num[ii] - '0'); + } +} + +BigNum::BigNum(const unsigned long num) { + stringstream ss; ss< result(new BigNum("0")); + if (digits.size() > addor.digits.size()) { + first = addor; + second = *this; + } else { + first = *this; + second = addor; + } + + int ii; + int carry = 0; + for (ii = 0; ii < first.digits.size(); ii++) { + const int sum = first.digits[ii] + second.digits[ii]; + result->digits.push_back((sum + carry) % base); + if (sum + carry > (base - 1)) { + carry = 1; + } else { + carry = 0; + } + } + + // finish up with the larger number + for (; ii < second.digits.size(); ii++) + if (carry) { + const int dig = (second.digits[ii] + carry); + result->digits.push_back(dig % base); + carry = (dig > (base - 1) ? dig / base : 0); + } else + result->digits.push_back(second.digits[ii]); + if (carry) + result->digits.push_back(carry); + + *this = *result; + return *this; +} + +BigNum &BigNum::operator*=(const int cc) { + // multiplies by small number cc + int carry = 0; + const unique_ptr result(new BigNum()); + + for (const int digit : digits) { + const int prod = digit * cc + carry; + result->digits.push_back(prod % base); + if (prod > (base - 1)) + carry = prod / base; + else + carry = 0; + } + + while (carry) { + result->digits.push_back(carry % base); + carry /= base; + } + + *this=*result; + return *this; +} + +BigNum &BigNum::operator*=(const BigNum& multiplicator) { + const unique_ptr sum(new BigNum()); + for (int ii = 0; ii < multiplicator.digits.size(); ii++) { + BigNum smallProd = *this * multiplicator.digits[ii]; + smallProd << ii; + *sum += smallProd; + } + *this = *sum; + return *this; +} + +BigNum &BigNum::operator/=(const BigNum& divisor) { + // pretty naive algorithm that is easy to implement + const unique_ptr guess(new BigNum()); + for (int ii = digits.size() - 1; ii >= 0; ii--) { + int dig; + BigNum trial(""); + for (dig = 9; dig > 0; dig--) { + BigNum num("1"); + num << ii; + trial = (num * dig); + if ((*guess + trial) * divisor <= *this) + break; + } + if (dig != 0) + *guess = *guess + trial; + } + if (guess->digits.size() == 1 && guess->digits[0] == 0) + guess->digits.pop_back(); // make it the empty representation + *this = *guess; + return *this; +} + +bool BigNum::operator==(const BigNum& otherNum) const { + if (digits.size() != otherNum.digits.size()) { + return false; + } + for (int ii = 0; ii < digits.size(); ii++) + if (digits[ii] != otherNum.digits[ii]) + return false; + return true; +} + +bool BigNum::operator<=(const BigNum& otherNum) const { + if (digits.size() > otherNum.digits.size()) + return false; + if (digits.size() < otherNum.digits.size()) + return true; + // same number of digits + for (int ii = digits.size() - 1; ii >= 0; ii--) + if (digits[ii] < otherNum.digits[ii]) + return true; + else if (digits[ii] > otherNum.digits[ii]) + return false; + return true; // they are equal +} + +void BigNum::operator<<(const int cc) { + digits.insert(digits.begin(), cc, 0); +} + +BigNum BigNum::operator*(const int cc) const { + BigNum *result = new BigNum(*this); + *result *= cc; + return *result; +} + +BigNum BigNum::operator+(const BigNum &addor) const { + BigNum result(*this); + result += addor; + return result; +} + +BigNum BigNum::operator*(const BigNum& multiplicator) const { + BigNum result(*this); + result *= multiplicator; + return result; +} + +BigNum BigNum::operator/(const BigNum& divisor) const { + BigNum result(*this); + result /= divisor; + return result; +} + +// friends and helpers +std::ostream & operator<<(std::ostream& stream, const BigNum& num) { + if (num.digits.size() == 0) + stream << "[0]"; + else + for (int ii = num.digits.size() - 1; ii >= 0; ii--) + stream << num.digits[ii]; + return stream; +} + diff --git a/tests/BigNum.h b/tests/BigNum.h new file mode 100644 index 0000000000000000000000000000000000000000..a661b9cf69bfff51fda01e92ec5c875e7414466a --- /dev/null +++ b/tests/BigNum.h @@ -0,0 +1,111 @@ +// +// Created by Ari Trachtenberg on 1/30/17. +// + +#ifndef HW1_BIGNUM_H +#define HW1_BIGNUM_H + + +// Written by Prof. Ari Trachtenberg for EC330 +#include +#include +using namespace std; + +/** + * A class to represent arbitrarily large non-negative integers. + */ +class BigNum { +public: + + // CONSTRUCTORS + + /** + * Constructs a bigNum from a given non-negative int + */ + BigNum(unsigned long num); + + /** + * Constructs a bigNum from a given string. + * @param num contains only characters 0-9 and represents a positive integer >= 0 + */ + explicit BigNum(const string &num = ""); + + /** + * Constructs a copy of {@code otherNum} + */ + BigNum(const BigNum& otherNum); + + // OPERATORS + /** + * @return true iff this bigNum is exactly numerically equal to otherNum + */ + bool operator==(const BigNum& otherNum) const; + + /** + * + * @param otherNum + * @return true iff this number is numerically less than or equal to other number + */ + bool operator<=(const BigNum& otherNum) const; + + /** + * This bigNum becomes the same as otherNum + * @return the (new) version of this bigNum + */ + BigNum& operator=(const BigNum& otherNum); + + /** + * @return the [index]-th least-significant digit of the number + */ + int operator[](const size_t index) const { return digits.at(index); } + + /** + * + * @return The number of significant digits in the number + */ + [[nodiscard]] size_t numDigits() const { return digits.size(); } + + /** + * Arithmetic + */ + BigNum operator+(const BigNum& addor) const; + BigNum operator*(const BigNum& multiplicator) const; + BigNum operator/(const BigNum& divisor) const; + + /** + * Optimized multiplication of a bigNum by an int + * @param cc > 0 is assumed + * @return the product of this number and cc + */ + BigNum operator*(int cc) const; + + /** + * ARITHMETIC ASSIGNMENT OPERATORS + */ + BigNum& operator+=(const BigNum& addor); + BigNum& operator*=(int cc); + BigNum& operator*=(const BigNum& multiplicator); + BigNum& operator/=(const BigNum& divisor); + +protected: + vector digits; /** stores the digits of the current number */ + + /** + * @param cc > 0 + * @return shifts the number to the left cc digits; + * equivalent to multiplying the current number by base^cc + */ + void operator<<(int cc); + +private: + // Constants + constexpr static int base = 10; // the base of the number + + // FRIENDS + /** + * Prints a human-readable version of bigNum [num] + * onto a given output stream + */ + friend std::ostream & operator<<(std::ostream& stream, const BigNum& num); +}; +#endif //HW1_BIGNUM_H diff --git a/tests/FullInteger.h b/tests/FullInteger.h new file mode 100644 index 0000000000000000000000000000000000000000..e22ba6c583fdaabe1cd67ffbc72b2fce5ed08ad1 --- /dev/null +++ b/tests/FullInteger.h @@ -0,0 +1,64 @@ +// +// Created by Ari on 2/22/26. +// + +#ifndef HW3_ADMIN_FULLINTEGER_H +#define HW3_ADMIN_FULLINTEGER_H +#include + +#include "IntegerP.h" +#include "IntegerPP.h" + +/** + * Represents a positive Integer of arbitrary precision, together with comparison and sorting capabilities. + */ +class FullInteger: public IntegerPP { + public: + /** + * All modeled after {@link IntegerPP}. + */ + FullInteger() = default; + FullInteger(unsigned long n) : IntegerPP(n) {} + FullInteger(std::initializer_list pBasis) : IntegerPP(pBasis) {} + FullInteger(const IntegerP& other) : IntegerPP(other) {} + explicit FullInteger(const BigNum& num) : IntegerPP(num) {} + FullInteger operator+(const FullInteger &addor) const { return IntegerPP::operator+(addor); } + FullInteger& operator=(const FullInteger& rhs) { IntegerPP::operator=(rhs); return *this; } + // new methods + /** + * @param other The {@link FullInteger} to which we are comparing. + * @return true iff this {@link FullInteger} is less than or equal to {@code other}. + */ + bool operator<=(const FullInteger &other) const; + + /** + * Sorts the given vector of FullIntegers in place based on {@link operator<=}. The + * FullIntegers must not have a single prime factor greater than {@largestPrimeFactor}, + * and functioning is unspecified if they do. + * @param largestPrimeFactor The largest prime factor of the FullIntegers provided. + * @param nums A vector of FullIntegers, none of whom have a prime factor greater than {@code largestPrimeFactor}. + * + * @example: + * vector nums = {3,1,4,1,5,9}; + * FullInteger::limitedSort(nums,5); + * transforms nums into the array {1,1,3,4,5,9} + * But FullInteger::limitedSort(nums,3) has unspecified execution because not all elements + * of the array have prime factors <= 3. + */ + static void limitedSort(vector& nums, int largestPrimeFactor); + + // ... derived methods + /** + * @param other The {@link FullInteger} to which we are comparing. + * @return true iff this {@link FullInteger} is less than {@code other}. + */ + bool operator<(const FullInteger &other) const { return operator<=(other) && !operator==(other); } + + /** + * @param other The {@link FullInteger} to which we are comparing. + * @return true iff this {@link FullInteger} is greater than {@code other}. + */ + bool operator>(const FullInteger &other) const { return !operator<=(other); } +}; + +#endif //HW3_ADMIN_FULLINTEGER_H \ No newline at end of file diff --git a/tests/IntegerP.cpp b/tests/IntegerP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..724f1ff699f03a93f6200e8de65f55241dcec6f9 --- /dev/null +++ b/tests/IntegerP.cpp @@ -0,0 +1,171 @@ +#include + +#include "../include/IntegerP.h" + +#include +#include +#include + +using namespace std; + +// helpers +/** + * @return true iff n is prime + */ +bool isPrime(const int n) { + if (n <= 1) + return false; + + for (int i = 2; i * i <= n; i++) { + if (n % i == 0) { + return false; + } + } + + return true; +} + +/** + * @return The i-th prime, starting with i-thPrime(0)==2. + */ +unsigned int ithPrime(const size_t ii) { + static auto memoized = vector(); + if (memoized.size()>ii && memoized[ii]!=0u) // i.e., already memoized + return memoized[ii]; + + int prime=2; + size_t ii_search=ii; + while (ii_search!=0) { + if (isPrime(++prime)) + ii_search--; + } + + memoized.resize(ii+1); + memoized[ii]=prime; + return prime; +} + +/** + * @return {@code v[i]} if {@code i} is within the range of {@code v}, or, {@code def} otherwise. + * @thanks ChatGPT + */ +template +T getOrDef(const std::vector& v, std::size_t i, T def = T{}) { + return i < v.size() ? v[i] : def; +} + +/** + * Computes a positive integer power of an integer, using square-and-multiply. + * @param base The base. + * @param exp The exponent + * @return base ^ exp + * @requires exp>=0 + * @thanks ChatGPT + */ +long ipow(int base, int exp) { + long result = 1; + + while (exp > 0) { + if (exp & 1) + result *= base; + base *= base; + exp >>= 1; + } + + return result; +} + +IntegerP::IntegerP(unsigned long lnum) { + int ii=-1; + while (lnum>1) { + ii++; + if (lnum % ithPrime(ii)==0) { + if (_primePowers.size()<=static_cast( ii )) // make sure that space is allocated + _primePowers.resize(ii+1); + _primePowers[ii]++; + lnum/=ithPrime(ii); + ii--; + } + } +} +IntegerP::IntegerP(const initializer_list pBasis):_primePowers(pBasis) { +} +IntegerP::IntegerP():IntegerP(1) { +} +// IntegerP IntegerP::operator+(const IntegerP &addend) { +// +// } +// IntegerP IntegerP::operator-(const IntegerP &subtrahend) { +// } +IntegerP IntegerP::operator*(const IntegerP &multiplicand) const { + const auto numIndices = static_cast(max(_primePowers.size(),multiplicand._primePowers.size())); + IntegerP result; + for (int ii=0; ii(max(_primePowers.size(),divisor._primePowers.size())); + IntegerP result; + int max_index=0; // the maximum significant index + for (int ii=0; ii log(LONG_MAX)) + return LONG_MAX; + + // size is ok + long result=1; + for (size_t ii=0; ii<_primePowers.size(); ii++) + result*=ipow(static_cast(ithPrime(ii)),_primePowers[ii]); + return result; +} + +bool IntegerP::divisibleBy(const IntegerP &divisor) const { + const IntegerP result = operator/(divisor); + for (const int exp:result._primePowers) + if (exp<0) + return false; + return true; +} +std::string IntegerP::toString() const { + ostringstream result; + + if (_primePowers.empty() || (_primePowers.size()==1 && _primePowers[0]==0)) + result << "1"; + else { + for (size_t ii=0; ii<_primePowers.size(); ii++) + if (_primePowers[ii]!=0) { + result << ithPrime(ii); + if (_primePowers[ii]!=1) + result << "^" << _primePowers[ii]; + if (ii<_primePowers.size()-1) + result << " * "; + } + } + return result.str(); +} diff --git a/tests/IntegerP.h b/tests/IntegerP.h new file mode 100644 index 0000000000000000000000000000000000000000..954727c08c3081b2d383617103aa81c06f914694 --- /dev/null +++ b/tests/IntegerP.h @@ -0,0 +1,127 @@ +// +// Created by Ari Trachtenberg on 1/23/26. +// + +#ifndef INITEGERP_H +#define INITEGERP_H +#include +#include + +/** + * Represents a multi-precision, positive Integer, in a manner suitable + * for efficiently multiplying and dividing large powers of small integers, + * such as 6^1000 and 10^512. + */ +class IntegerP { + public: + // CONSTRUCTORS + /** + * Constructs the Integer 1. + */ + IntegerP(); + + /** + * Constructs an {@link IntegerP} representation of num. + * @requires num>0 + */ + IntegerP(unsigned long lnum); + + /** + * Constructs a representation of an integer in the prime basis. + * Specifically, the number produced is: + * product over all i of (prime(i)^basis[i]), + * where prime(i) is the i-th prime number (2 being the 0-th prime), and + * basis[i] is the i-th element of parameter {@code pBasis}. + * @param pBasis A list representing the powers of primes generating this {@link IntegerP}. + * @requires pBasis[i]>=0 for all i + * @example IntegerP ({1}) represents the number 2 = 2^1 + * @example IntegerP ({1,1}) represents the number 6 = 2^1 * 3^1 + * @example IntegerP ({1,0,0,1}) represents the number 14 = 2^1 * 3^0 * 5^0 * 7^1 + * @example IntegerP ({0,2,0,1,1}) represents the number 693 = 3^2 * 7 * 11 + */ + IntegerP(std::initializer_list pBasis); + + /** + * Static factory method based on {@link #IntegerP(unsigned long)}. + * @example IntegerP::valueOf(3) returns an IntegerP representing 3 = 3^1. + */ + static IntegerP valueOf(const unsigned long lnum) { + return IntegerP(lnum); + } + + /** + * Static factory method based on {@link #IntegerP(std::initializer_list)}. + * @example IntegerP::valueOf({1}) represents the number 2 = 2^1 + * @example IntegerP::valueOf({1,1}) represents the number 6 = 2^1 * 3^1 + * @example IntegerP::valueOf({1,0,0,1}) represents the number 14 = 2^1 * 3^0 * 5^0 * 7^1 + * @example IntegerP::valueOf({0,2,0,1,1}) represents the number 693 = 3^2 * 7 * 11 + */ + static IntegerP valueOf(const std::initializer_list pBasis) { + return IntegerP(pBasis); + } + + // OPERATORS + /** + * Multiplies this {@link IntegerP} by {@code multiplicand} and returns the product. + * @param multiplicand The number to multiply by this object. + * @return The product of this object and {@code multiplicand}. + * @example IntegerP::valueOf(10) * Integer::valueOf(5) = Integer::valueOf(50) + * @example IntegerP::valueOf({1,1}) * IntegerP::valueOf({1,0,0,1}) = IntegerP::valueOf({2,1,0,1}) + * (2*3) * (2*7) = (2^2 * 3 * 7) + * 6 * 14 = 84 + */ + IntegerP operator*(const IntegerP &multiplicand) const; + + /** + * Divides this {@link IntegerP} by {@code divisor} and returns the quotient. + * @param divisor The number into which to divide this object. + * @return The division of this object and {@code divisor}. If this object is not + * evenly divisible by {@code divisor}, the result is not specified. + * @example IntegerP::valueOf(14) / IntegerP::valueOf(2) = IntegerP::valueOf(7) + */ + IntegerP operator/(const IntegerP &divisor) const; + + /** + * @return true iff {@code other} is *identical* to this Rational number + * @example IntegerP::valueOf(14)==Integer::valueOf({1,0,0,1}) returns true + */ + bool operator==(const IntegerP &other) const; + + // INFORMATIONAL + /** + * @return A truncation of this object to a {@code long}, or + * LONG_MAX if the object represents a number that is too big + * to fit in a {@code long}. + * @example IntegerP::valueOf(14).trunc() returns 14 + * @example IntegerP::valueOf({2,1,0,1}).trunc() returns 84 + * @example IntegerP::valueOf({20,3,5,10}).trunc() retunrs LONG_MAX (=9223372036854775807) + */ + [[nodiscard]] long trunc() const; + + /** + * @param divisor The divisor to check for divisibility + * @return true iff this object is evenly divisible by {@code divisor}. + * @example IntegerP::valueOf(14).divisibleBy(IntegerP::valueOf(2)) returns true + * @example IntegerP::valueOf(14).divisibleBy(IntegerP::valueOf(3)) returns false + */ + bool divisibleBy(const IntegerP &divisor) const; + + /** + * @return A human-readable representation of this object. + * @example IntegerP::valueOf(2928).toString() may return "2^4 * 3 * 61" + */ + std::string toString() const; + + /** + * Safe getter method for the {@link #_primePowers} field. + * @return A read-only version of {@link #_primePowers}. + */ + const std::vector& primePowers() const noexcept { return _primePowers; } + + protected: + /** + * the i-th entry contains the power of i-th prime in the product that generates this object. + */ + std::vector _primePowers; +}; +#endif //IntegerP_H diff --git a/tests/IntegerPP.cpp b/tests/IntegerPP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ca1db47dc8f20c1d4789bb209cd876c45aa9e2d --- /dev/null +++ b/tests/IntegerPP.cpp @@ -0,0 +1,106 @@ +// +// Created by Ari on 1/31/26. +// + +#include "../include/IntegerPP.h" + +bool isDivisible(const BigNum& num, const BigNum& divisor) { + return divisor*(num/divisor)==num; +} + +bool isPrimePlus(const BigNum& n) { + if (n <= 1) + return false; + + for (BigNum i = 2; i * i <= n; i=i+1) { + if (isDivisible(n,i)) { + return false; + } + } + + return true; +} + +/** + * @return The i-th prime, starting with i-thPrime(0)==2. + */ +BigNum ithPrimePlus(const size_t ii) { + static auto memoized = vector(); + if (memoized.size()>ii) // i.e., already memoized + return memoized[ii]; + + BigNum prime=2; + size_t ii_search=ii; + while (ii_search!=0) { + prime = prime + 1; + if (isPrimePlus(prime)) + ii_search--; + } + + memoized.resize(ii+1); + memoized[ii]=prime; + return prime; +} + +/** + * Computes a positive integer power of an integer, using square-and-multiply. + * @param base The base. + * @param exp The exponent + * @return base ^ exp + * @requires exp>=0 + * @thanks ChatGPT + */ +BigNum ipowPlus(BigNum base, int exp) { + BigNum result = 1; + + while (exp > 0) { + if (exp & 1) + result *= base; + base *= base; + exp >>= 1; + } + + return result; +} + +// return true iff num1 > num2 +bool BigNumGreater(const BigNum& num1, const BigNum& num2) { + return (num2<=num1) && (!(num1==num2)); +} + +IntegerPP::IntegerPP(BigNum num) { + int ii=-1; + while (BigNumGreater(num,1)) { + ii++; + if (isDivisible(num, ithPrimePlus(ii))) { + if (_primePowers.size()<=static_cast(ii) ) // make sure that space is allocated + _primePowers.resize(ii+1); + _primePowers[ii]++; + num/=ithPrimePlus(ii); + ii--; + } + } +} + +IntegerPP::operator BigNum() const { + BigNum result=1; + for (size_t ii=0; ii<_primePowers.size(); ii++) { + result*=ipowPlus(ithPrimePlus(ii),_primePowers[ii]); + } + return result; +} + +IntegerPP IntegerPP::operator+(const IntegerPP &addor) const { + return IntegerPP(static_cast(*this) + static_cast(addor)); +} +IntegerPP & IntegerPP::operator=(const IntegerPP &rhs) { + if (this !=& rhs) { + _primePowers=rhs._primePowers; + } + return *this; +} + +IntegerPP::IntegerPP() = default; +IntegerPP::IntegerPP(unsigned long n):IntegerP(n) {} +IntegerPP::IntegerPP(std::initializer_list pBasis):IntegerP(pBasis) {} +IntegerPP::IntegerPP(const IntegerP& other):IntegerP(other) {} \ No newline at end of file diff --git a/tests/IntegerPP.h b/tests/IntegerPP.h new file mode 100644 index 0000000000000000000000000000000000000000..6aadb6d8e76631c85cfd5b6600067b90dbf49187 --- /dev/null +++ b/tests/IntegerPP.h @@ -0,0 +1,51 @@ +// +// Created by Ari on 1/31/26. +// + +#ifndef HW1_INTEGERPLUS_H +#define HW1_INTEGERPLUS_H +#include "IntegerP.h" +#include "BigNum.h" + +class IntegerPP: public IntegerP { + public: + /** + * All modeled after {@link IntegerP}. + */ + IntegerPP(); + IntegerPP(unsigned long n); + IntegerPP(std::initializer_list pBasis); + IntegerPP(const IntegerP& other); + + + /** + * Constructs an IntegerPlus from a BigNum + * @param num The BigNum from which to construct the IntegerPlus. + */ + explicit IntegerPP(BigNum num); + + /** + * Adds this {@link IntegerPP} by {@code addor} and returns the sum. + * @param addor The number to add to this object. + * @return The sum of this object and {@code addor}. + * @example IntegerPP(10) + IntegerPP(5) == IntegerPP(15) + * @example IntegerPP({1,1}) * IntegerPP({1,0,0,1}) == IntegerPP({2,0,1}) + * (2*3) + (2*7) = (2^2 * 5) + * 6 + 14 = 20 + */ + IntegerPP operator+(const IntegerPP &addor) const; + + /** + * Assigns the {@link rhs} to this object. + * @param rhs The element to assign. + * @return this object. + */ + IntegerPP& operator=(const IntegerPP& rhs); + + /** + * Converts this IntegerPP into a BigNum. + */ + explicit operator BigNum() const; +}; + +#endif //HW1_INTEGERPLUS_H \ No newline at end of file diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1e1f701fca4b366402861850e13aadd3f13f5d5e --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,32 @@ +# Makefile, generated with support of ChatGPT + +# Compiler and flags +CXX = g++ -O2 +CXXFLAGS = -std=c++17 + +# Source files +PROBLEM3_SRCS = testFullInteger.cpp FullInteger.cpp IntegerPP.cpp IntegerP.cpp BigNum.cpp +SRCS = $(PROBLEM3_SRCS) + +# Object files +PROBLEM3_OBJS = testFullInteger.o FullInteger.o IntegerPP.o IntegerP.o BigNum.o +OBJS = $(PROBLEM3_OBJS) + +# Executable name +PROBLEM3_EXEC = problem3 +EXECS = $(PROBLEM3_EXEC) + +# Default target to build the executable +all: $(PROBLEM3_EXEC) + +# Rule to build the executable from object files +$(PROBLEM3_EXEC): $(PROBLEM3_OBJS) Makefile + $(CXX) $(CXXFLAGS) -o $(PROBLEM3_EXEC) $(PROBLEM3_OBJS) + +# Rules to build object files from source files +%.o: %.cpp Makefile + $(CXX) $(CXXFLAGS) -c $< -o $@ + +# Clean target to remove compiled files +clean: + rm -f $(OBJS) $(EXECS) \ No newline at end of file diff --git a/tests/testFullInteger.cpp b/tests/testFullInteger.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a6c81b2dbd5f4559b21793f70edc12b656e73cc5 --- /dev/null +++ b/tests/testFullInteger.cpp @@ -0,0 +1,80 @@ +// +// Developed by Rayan on 2/23/26. Adapted from Ari's tests for IntegerP +// +#include +#include +#include + +#include "FullInteger.h" + +using namespace std; + +// helper function +bool failExample(const char* testName, const std::string& msg, string expected, string got) { + std::cerr << "[" << testName << " FAILED] " << msg << ": expected " << expected << ", got " << got << "\n"; + return false; +} + +// Assisted by ChatGPT +// -------------------- operator<= and limitedSort -------------------- +bool test_0() { + const char* T = "FullInteger examples"; + + { + // Basic operator<= sanity checks + if (!(FullInteger(1) <= FullInteger(1))) + return failExample(T, "FullInteger(1) <= FullInteger(1)", "true", "false"); + + if (!(FullInteger(1) <= FullInteger(2))) + return failExample(T, "FullInteger(1) <= FullInteger(2)", "true", "false"); + + if (FullInteger(2) <= FullInteger(1)) + return failExample(T, "FullInteger(2) <= FullInteger(1)", "false", "true"); + } + + { + // @example: + // vector nums = {3,1,4,1,5,9}; + // FullInteger::limitedSort(nums,5); + // transforms nums into the array {1,1,3,4,5,9} + vector nums = {3,1,4,1,5,9}; + FullInteger::limitedSort(nums, 5); + + vector expected = {1,1,3,4,5,9}; + + if (nums.size() != expected.size()) + return failExample(T, "limitedSort output size matches expected", "true", "false"); + + for (size_t i = 0; i < nums.size(); i++) { + if (!(nums[i] == expected[i])) { + return failExample( + T, + "FullInteger::limitedSort(nums,5) sorts {3,1,4,1,5,9} into {1,1,3,4,5,9}", + "true", + "false" + ); + } + } + } + + return true; +} + +int main() { + bool results[] = { test_0() }; + + bool allPassed = true; + for (size_t ii=0; ii