Commit 68bdaaa6 authored by Ari Trachtenberg's avatar Ari Trachtenberg
Browse files

Added test cases.

parent ffa1eaba
Loading
Loading
Loading
Loading

tests/IntegerP.h

0 → 100644
+129 −0
Original line number Diff line number Diff line
//
// Created by Ari Trachtenberg on 1/23/26.
//

#ifndef INITEGERP_H
#define INITEGERP_H
#include <vector>
#include <string>

/**
 * 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<int> 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<int>)}.
     * @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<int> 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)
     * @example IntegerP::valueOf(14) / IntegerP::valueOf(3) throws indivisible_exception
     *          14 / 3 is not an integer.
     */
    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 82
     * @example IntegerP::valueOf({20,3,5,10}).trunc() retunrs LONG_MAX (=9223372036854775807)
     */
    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<int>& 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<int> _primePowers;
};
#endif //IntegerP_H

tests/Makefile

0 → 100644
+38 −0
Original line number Diff line number Diff line
# Makefile, generated with support of ChatGPT

# Compiler and flags
CXX = g++ -O2
CXXFLAGS = -Wall -std=c++17

# Source files
PROBLEM0_SRCS = testIntegerP.cpp IntegerP.cpp
PROBLEM1_SRCS = testRationalP.cpp RationalP.cpp IntegerP.cpp
SRCS = $(PROBLEM0_SRCS) $(PROBLEM1_SRCS)

# Object files
PROBLEM0_OBJS = testIntegerP.o IntegerP.o
PROBLEM1_OBJS = testRationalP.o RationalP.o IntegerP.o
OBJS = $(PROBLEM0_OBJS) $(PROBLEM1_OBJS)

# Executable names
PROBLEM0_EXEC = problem0
PROBLEM1_EXEC = problem1

# Default target to build the executable
all: $(PROBLEM0_EXEC) $(PROBLEM1_EXEC)

# Rule to build the executable from object files
$(PROBLEM0_EXEC): $(PROBLEM0_OBJS) Makefile
	$(CXX) $(CXXFLAGS) -o $(PROBLEM0_EXEC) $(PROBLEM0_OBJS)

$(PROBLEM1_EXEC): $(PROBLEM1_OBJS) Makefile
	$(CXX) $(CXXFLAGS) -o $(PROBLEM1_EXEC) $(PROBLEM1_OBJS)

# Rules to build object files from source files, with dependency on the Common.h header
%.o: %.cpp %.h Makefile
	$(CXX) $(CXXFLAGS) -c $< -o $@

# Clean target to remove compiled files
clean:
	rm -f $(OBJS) $(EXEC)

tests/RationalP.h

0 → 100644
+88 −0
Original line number Diff line number Diff line
//
// Created by Ari Trachtenberg on 1/23/26.
//

#ifndef RATIONALP_H
#define RATIONALP_H
#include "IntegerP.h"

/**
 * Represents a multi-precision rational number, in a manner suitable
 * for manipulating large and small powers, such as 2^1000 or (3/2)^-1000.
 */
class RationalP : public IntegerP {
  public:
    // CONSTRUCTORS

    /**
     * Constructs the Rational 1.
     */
    RationalP();

    /**
     * Constructs a RationalP representing the IntegerP {@code intp}.
     */
    explicit RationalP(const IntegerP &intp);

    /**
     * Produces a representation of num / denom.
     * @requires denom != 0
     */
    RationalP(const IntegerP &num, const IntegerP &denom);

    /**
     * {@inheritDoc}
     * @param pBasis Components may be negative, zero, or positive
     */
    RationalP(const std::initializer_list<int> &pBasis);

    /**
     * @param num The numerator
     * @param denom The denominator
     * @requires denom != 0
     * @return A RationalP representing num / denom.
     */
    static RationalP valueOf(const IntegerP &num, const IntegerP &denom);

    /**
     * {@inheritDoc}
     * @param pBasis Components may be negative, zero, or positive
     */
    static RationalP valueOf(std::initializer_list<int> pBasis);


    // OPERATORS

    /**
     * {@inheritDoc}
     */
    RationalP operator*(const RationalP &multiplicand) const;

    /**
     * {@inheritDoc}
     */
    RationalP operator/(const RationalP &divisor) const;

    /**
     * {@inheritDoc}
     */
    bool operator==(const RationalP &other) const;


    // INFORMATIONAL
    /**
     * @return An approximation of this Rational number, expressed as a long double.
     */
    long double trunc() const;

    /**
     * {@inheritDoc}
     */
    bool divisibleBy(const RationalP &other) const;

    /**
     * {@inheritDoc}
     */
    std::string toString() const;
};
#endif //RATIONALP_H

tests/testIntegerP.cpp

0 → 100644
+211 −0
Original line number Diff line number Diff line
//
// Created by Ari on 1/26/26.
//
#include <iostream>
#include <climits>
#include <string>

#include "IntegerP.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
// -------------------- Constructor --------------------
bool test_0() {
  const char* T = "Constructor examples";

  {
    IntegerP x;
    if (x.trunc() != 1) return failExample(T, "IntegerP x","1",to_string(x.trunc()));
  }

  {
    IntegerP x(13);
    if (x.trunc() != 13) return failExample(T, "IntegerP x","13",to_string(x.trunc()));
  }

  {
    IntegerP x({1}); // 2
    if (x.trunc() != 2) return failExample(T, "IntegerP({1})","2",to_string(x.trunc()));
  }

  {
    IntegerP x({1,1}); // 6
    if (x.trunc() != 6) return failExample(T, "IntegerP({1,1})","6",to_string(x.trunc()));
  }

  {
    IntegerP x({1,0,0,1}); // 14
    if (x.trunc() != 14) return failExample(T, "IntegerP({1,0,0,1})","14",to_string(x.trunc()));
  }

  {
    IntegerP x({0,2,0,1,1}); // 693
    if (x.trunc() != 693) return failExample(T, "IntegerP({0,2,0,1,1})","693",to_string(x.trunc()));
  }
  return true;
}

// -------------------- IntegerP::valueOf(unsigned long) --------------------
bool test_1() {
  const char* T = "IntegerP::valueOf(unsigned long) examples";

  {
    IntegerP x = IntegerP::valueOf(3);
    if (x.trunc() != 3) return failExample(T, "valueOf(3)","3",to_string(x.trunc()));
  }

  return true;
}

// -------------------- IntegerP::valueOf(std::initializer_list<int>) --------------------
bool test_2() {
  const char* T = "IntegerP::valueOf(std::initializer_list<int>) examples";

  {
    IntegerP x = IntegerP::valueOf({1});
    if (x.trunc() != 2) return failExample(T, "valueOf({1})","2",to_string(x.trunc()));
  }

  {
    IntegerP x = IntegerP::valueOf({1,1});
    if (x.trunc() != 6) return failExample(T, "valueOf({1,1})","6",to_string(x.trunc()));
  }

  {
    IntegerP x = IntegerP::valueOf({1,0,0,1});
    if (x.trunc() != 14) return failExample(T, "valueOf({1,0,0,1})","14",to_string(x.trunc()));
  }
  {
    IntegerP x = IntegerP::valueOf({0,2,0,1,1});
    if (x.trunc() != 693) return failExample(T, "valueOf({0,2,0,1,1})","693",to_string(x.trunc()));
  }

  return true;
}

// -------------------- operator* --------------------
bool test_3() {
  const char* T = "IntegerP::operator* examples";

  {
    IntegerP a = IntegerP::valueOf(10);
    IntegerP b = IntegerP::valueOf(5);
    IntegerP got = a * b;
    IntegerP expected = IntegerP::valueOf(50);
    if (!(got == expected)) return failExample(T, "valueOf(10) * valueOf(5)","50",got.toString());
  }
  {
    IntegerP a = IntegerP::valueOf({1,1});         // 6
    IntegerP b = IntegerP::valueOf({1,0,0,1});     // 14
    IntegerP got = a * b;
    IntegerP expected = IntegerP::valueOf({2,1,0,1}); // 84
    if (!(got == expected)) return failExample(T, "valueOf({1,1}) * valueOf({1,0,0,1}) should equal valueOf({2,1,0,1})","true","false");
  }

  return true;
}

// -------------------- operator/ --------------------
bool test_4() {
  const char* T = "IntegerP::operator/ examples";

  {
    IntegerP a = IntegerP::valueOf(14);
    IntegerP b = IntegerP::valueOf(2);
    IntegerP got = a / b;
    IntegerP expected = IntegerP::valueOf(7);
    if (!(got == expected)) return failExample(T, "valueOf(14) / valueOf(2)","7",got.toString());
  }

  return true;
}

// -------------------- operator== --------------------
bool test_5() {
  const char* T = "IntegerP::operator== examples";

  {
    IntegerP a = IntegerP::valueOf(14);
    IntegerP b = IntegerP::valueOf({1,0,0,1});
    if (!(a == b)) return failExample(T, "valueOf(14) == valueOf({1,0,0,1})","true","false");
  }

  return true;
}

// -------------------- trunc() --------------------
bool test_6() {
  const char* T = "IntegerP::trunc examples";

  {
    if (IntegerP::valueOf(14).trunc() != 14)
      return failExample(T, "valueOf(14).trunc()","14",to_string(IntegerP::valueOf(14).trunc()));
  }
  {

    if (IntegerP::valueOf({2,1,0,1}).trunc() != 84)
      return failExample(T, "valueOf({2,1,0,1})","84",to_string(IntegerP::valueOf({2,1,0,1}).trunc()));
  }
  {
    if (IntegerP::valueOf({20,3,5,10}).trunc() != LONG_MAX)
      return failExample(T, "valueOf({20,3,5,10}).trunc()",to_string(LONG_MAX),to_string(IntegerP::valueOf({20,3,5,10}).trunc()));
  }

  return true;
}

// -------------------- divisibleBy() --------------------
bool test_7() {
  const char* T = "IntegerP::divisibleBy examples";

  {
    if (!IntegerP::valueOf(14).divisibleBy(IntegerP::valueOf(2)))
      return failExample(T, "valueOf(14).divisibleBy(valueOf(2))","true","false");
  }
  {
    if (IntegerP::valueOf(14).divisibleBy(IntegerP::valueOf(3)))
      return failExample(T, "valueOf(14).divisibleBy(valueOf(3))","false","true");
  }

  return true;
}

// -------------------- toString() --------------------
bool test_8() {
  const char* T = "IntegerP::toString examples";

  {
    // "may return ..." => only enforce non-empty.
    std::string s = IntegerP::valueOf(2928).toString();
    if (s.empty()) return failExample(T, "valueOf(2928).toString()","non-empty string",s);
  }

  return true;
}


int main() {
  bool results[] = { test_0(), test_1(), test_2(), test_3(), test_4(), test_5(), test_6(), test_7(), test_8() };

  bool allPassed = true;
  for (int ii=0; ii<sizeof(results)/sizeof(results[0]);ii++) {
    cout << "Test of problem " << to_string(ii) << ": " << (results[ii] ? "passed" : "failed") << endl;
    allPassed &= results[ii];
  }

  if (allPassed) {
    // all tests passed
    exit(0);
  }
  else {
    // at least one test was failed
    exit (-1);
  }
}
+188 −0
Original line number Diff line number Diff line
//
// Created by Ari on 1/26/26.
//
#include <iostream>
#include <climits>
#include <string>

#include "RationalP.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;
}

/**
 * @return true when a and b are "approximately" equal
 */
bool approxEq(long double a, long double b) {
  if (a/b > 0.9 && a/b < 1.1) {
    return true;
  }
  else {
    return false;
  }
}

// Assisted by ChatGPT
// -------------------- Constructor --------------------
bool test_0() {
  const char* T = "Constructor examples";

  {
    RationalP x;
    if (x.trunc() != 1) return failExample(T, "RationalP x","1",to_string(x.trunc()));
  }

  {
    RationalP x({1}); // 2
    if (x.trunc() != 2) return failExample(T, "RationalP({1})","2",to_string(x.trunc()));
  }

  {
    RationalP x({1},{0,1}); // 2/3
    if (!approxEq(x.trunc() , 2.0L/3.0L)) return failExample(T, "RationalP x({1},{0,1})","2/3",to_string(x.trunc()));
  }

  {
    RationalP x({1,0,0,-1,1}); // 22/7
    if (!approxEq(x.trunc() , 22.0L/7.0L)) return failExample(T, "RationalP x({1,0,0,-1,1})","22/7",to_string(x.trunc()));
  }
  return true;
}

// -------------------- RationalP::valueOf --------------------
bool test_1() {
  const char* T = "RationalP::valueOf examples";

  {
    RationalP x = RationalP::valueOf(3,2);
    if (!approxEq(x.trunc() , 3.0L/2.0L)) return failExample(T, "valueOf(3,2)","3/2",to_string(x.trunc()));
  }

  {
    RationalP x = RationalP::valueOf({1,0,0,-1,1}); // 22/7
    if (!approxEq(x.trunc() , 22.0L/7.0L)) return failExample(T, "Rational::valueOf(1,0,0,-1,1)","22/7",to_string(x.trunc()));
  }

  return true;
}


// -------------------- operator* --------------------
bool test_2() {
  const char* T = "operator* examples";

  {
    RationalP a = RationalP::valueOf(22,7); // 22/7
    RationalP b (7); // 7
    RationalP got = a * b;
    RationalP expected = RationalP(IntegerP(22));
    if (!(got == expected)) return failExample(T, "22/7 * 7","22",got.toString());
  }
  {
    RationalP a = RationalP::valueOf(3,4);     // 3/4
    RationalP b = RationalP::valueOf(4,3);     // 4/3
    RationalP got = a * b;
    RationalP expected; // 1
    if (!(got == expected)) return failExample(T, "3/4 * 4/3",expected.toString(),got.toString());
  }

  return true;
}

// -------------------- operator/ --------------------
bool test_3() {
  const char* T = "operator/ examples";

  {
    RationalP a = RationalP(IntegerP(14)); // 14
    RationalP b = RationalP(IntegerP(6));   // 6
    RationalP got = a / b;
    RationalP expected = RationalP::valueOf(7,3); // 7/3
    if (!(got == expected)) return failExample(T, "14/6","7/3",got.toString());
  }

  return true;
}

// -------------------- operator== --------------------
bool test_4() {
  const char* T = "IntegerP::operator== examples";

  {
    RationalP a = RationalP(7,8);
    RationalP b = RationalP(IntegerP(7)) / RationalP(IntegerP(8));
    if (!(a == b)) return failExample(T, "7/8 == (7/1) / (8/1))","true","false");
  }

  return true;
}

// -------------------- trunc() --------------------
bool test_5() {
  const char* T = "IntegerP::trunc examples";

  {
    RationalP x = RationalP::valueOf(333,106);
    if (!approxEq(x.trunc() , 333.0L/106L))
      return failExample(T, "(333/106).trunc()","3.14150943",to_string(x.trunc()));
  }
  return true;
}

// -------------------- divisibleBy() --------------------
bool test_6() {
    const char* T = "divisibleBy examples";

    {
      if (!RationalP(IntegerP(14)).divisibleBy(RationalP(IntegerP(2))))
        return failExample(T, "14 divisibleBy 2","true","false");
    }
    {
      if (!RationalP(7,2).divisibleBy(RationalP(1,2)))
        return failExample(T, "7/2 divisibleBy 1/2","true","false");
    }
    {
      if (RationalP(7,3).divisibleBy(RationalP(1,2)))
        return failExample(T, "7/3 divisibleBy 1/2","false","true");
    }

    return true;
  }

// -------------------- toString() --------------------
bool test_7() {
  const char* T = "IntegerP::toString examples";

  {
    // "may return ..." => only enforce non-empty.
    std::string s = RationalP::valueOf(123,456).toString();
    if (s.empty()) return failExample(T, "(123/456).toString()","non-empty string",s);
  }

  return true;
}


int main() {
  bool results[] = { test_0(), test_1(), test_2(), test_3(), test_4(), test_5(), test_6(), test_7() };

  bool allPassed = true;
  for (int ii=0; ii<sizeof(results)/sizeof(results[0]);ii++) {
    cout << "Test of problem " << to_string(ii) << ": " << (results[ii] ? "passed" : "failed") << endl;
    allPassed &= results[ii];
  }

  if (allPassed) {
    // all tests passed
    exit(0);
  }
  else {
    // at least one test was failed
    exit (-1);
  }
}