Last active
November 7, 2019 18:52
-
-
Save dulimarta/90f00054c518ba2a7b81a5d7441c3fc2 to your computer and use it in GitHub Desktop.
CIS343 C++ Fraction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.14) | |
project(Fraction) | |
set(CMAKE_CXX_COMPILER clang++) | |
set(CMAKE_CXX_STANDARD 17) | |
set(CMAKE_CXX_FLAGS "-g -Wall") | |
include_directories(.) | |
add_executable(runtest | |
Fraction.cpp | |
Fraction.h | |
runtest.cpp) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Fraction.h" | |
#include <algorithm> | |
#include <iomanip> | |
#include <regex> | |
using namespace std; | |
/* Friend functions */ | |
Fraction operator+(int val, const Fraction &f) { return {}; } | |
Fraction operator-(int val, const Fraction &f) { return {}; } | |
Fraction operator*(int val, const Fraction &f) { return {}; } | |
Fraction::Fraction() {} | |
Fraction::Fraction(int v) {} | |
Fraction::Fraction(const Fraction &other) {} | |
Fraction::Fraction(Fraction &&other) {} | |
Fraction::Fraction(std::string s) {} | |
int Fraction::whole() const { return -1; } | |
int Fraction::numerator() const { return -1; } | |
int Fraction::denominator() const { return -1; } | |
bool Fraction::isPositive() const { return false; } | |
Fraction& Fraction::operator=(const Fraction &other) { return *this; } | |
Fraction& Fraction::operator=(Fraction &&other) { return *this; } | |
Fraction Fraction::operator+(int num) const { return {}; } | |
Fraction Fraction::operator+(const Fraction &other) const { return {}; } | |
Fraction Fraction::operator-() const { return {}; } | |
Fraction Fraction::operator-(int val) const { return {}; } | |
Fraction Fraction::operator-(const Fraction &other) const { return {}; } | |
Fraction Fraction::operator*(int val) const { return {}; } | |
Fraction Fraction::operator*(const Fraction &other) const { return {}; } | |
optional<int> Fraction::operator[](int pos) const { return {}; } | |
bool Fraction::operator<(const Fraction &other) const { return {}; } | |
bool Fraction::operator==(const Fraction &other) const { return {}; } | |
void Fraction::makeProper() {} | |
Fraction Fraction::toProper() const { return {}; } | |
void Fraction::reduce() {} | |
Fraction Fraction::toReduced() const { return {}; } | |
ostream &Fraction::writeTo(ostream &os) const { return os; } | |
istream &Fraction::readFrom(istream &sr) /*throw(std::invalid_argument) */ { | |
return sr; | |
} | |
bool Fraction::isReduced() const { return {}; } | |
bool Fraction::isProper() const { return {}; } | |
ostream &operator<<(ostream &os, const Fraction &f) { return os; } | |
istream &operator>>(istream &s, Fraction &f) { return s; } | |
#if I_DO_EXTRA_CREDIT | |
optional<string> Fraction::isRepeating() const { return {}; } | |
string Fraction::operator()(int len) const { return {}; } | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <iostream> | |
#include <optional> | |
#include <string> | |
using std::istream; | |
using std::optional; | |
using std::ostream; | |
using std::string; | |
class Fraction { | |
friend ostream &operator<<(ostream &, const Fraction &); | |
friend istream &operator>>(istream &, Fraction &); | |
friend Fraction operator+(int, const Fraction &); | |
friend Fraction operator-(int, const Fraction &); | |
friend Fraction operator*(int, const Fraction &); | |
public: | |
/* Constructors */ | |
Fraction(); | |
Fraction(int); | |
Fraction(string); | |
Fraction(const Fraction &); | |
Fraction(Fraction &&); | |
// Access functions | |
int whole() const; | |
int numerator() const; | |
int denominator() const; | |
bool isPositive() const; | |
// Conversion functions | |
void reduce(); // Convert fraction to reduced form | |
void makeProper(); // Convert fraction to proper form | |
Fraction toProper() const; | |
Fraction toReduced() const; | |
bool isReduced() const; | |
bool isProper() const; | |
// Operator functions | |
Fraction &operator=(const Fraction &); // Copy assignment | |
Fraction &operator=(Fraction &&); // Move assignment | |
Fraction operator+(int) const; // Add Fraction + int | |
Fraction operator+(const Fraction &) const; // Add Fraction + Fraction | |
Fraction operator-() const; // unary minus | |
Fraction operator-(int) const; // binary minus: Frac - int | |
Fraction operator-(const Fraction &) const; // binary minus: Frac - Frac | |
Fraction operator*(int)const; // Multiply: Frac * int | |
Fraction operator*(const Fraction &)const; // Multiply: Frac * Frac | |
bool operator<(const Fraction &) const; // Compare Frac < Frac | |
bool operator==(const Fraction &) const; // Compare Frac == Frac | |
optional<int> operator[](int) const; // Component access Frac[i] | |
#if I_DO_EXTRA_CREDIT | |
// Implement these two OR add your own operator(s) | |
optional<string> isRepeating() const; | |
string operator()(int) const; | |
#endif | |
private: | |
ostream &writeTo(ostream &) const; | |
istream &readFrom(istream &); | |
}; | |
/* Friend functions (non-member functions) */ | |
ostream &operator<<(ostream &, const Fraction &); | |
istream &operator>>(istream &, Fraction &); | |
Fraction operator+(int, const Fraction &); // Add: int + Fraction |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define CATCH_CONFIG_MAIN | |
#include "Fraction.h" | |
#include "catch.hh" | |
#include <sstream> | |
using std::istringstream; | |
using std::ostringstream; | |
TEST_CASE("Constructor") { | |
SECTION("Default") { | |
Fraction x; | |
CHECK(x.whole() == 0); | |
CHECK(x.numerator() == 0); | |
CHECK(x.denominator() == 1); | |
} | |
SECTION("Construct from whole number", "Positive") { | |
Fraction z{2}; | |
CHECK(z.whole() == 2); | |
CHECK(z.numerator() == 0); | |
CHECK(z.denominator() == 1); | |
CHECK(z.isPositive()); | |
} | |
SECTION("Construct from whole number", "Negative") { | |
Fraction z{-2}; | |
CHECK(z.whole() == 2); | |
CHECK(z.numerator() == 0); | |
CHECK(z.denominator() == 1); | |
CHECK_FALSE(z.isPositive()); | |
} | |
SECTION("Construct from std::string", "Positive") { | |
Fraction a{"3"}; | |
Fraction b{"1 7/13"}; | |
Fraction c{"8/17"}; | |
CHECK(a.whole() == 3); | |
CHECK(a.numerator() == 0); | |
CHECK(a.denominator() == 1); | |
CHECK(a.isPositive()); | |
CHECK(b.whole() == 1); | |
CHECK(b.numerator() == 7); | |
CHECK(b.denominator() == 13); | |
CHECK(b.isPositive()); | |
CHECK(c.whole() == 0); | |
CHECK(c.numerator() == 8); | |
CHECK(c.denominator() == 17); | |
CHECK(b.isPositive()); | |
} | |
SECTION("Construct from std::string", "Negative") { | |
Fraction a{"-3"}; | |
Fraction b{"-1 7/13"}; | |
Fraction c{"-8/17"}; | |
CHECK(a.whole() == 3); | |
CHECK(a.numerator() == 0); | |
CHECK(a.denominator() == 1); | |
CHECK_FALSE(a.isPositive()); | |
CHECK(b.whole() == 1); | |
CHECK(b.numerator() == 7); | |
CHECK(b.denominator() == 13); | |
CHECK_FALSE(b.isPositive()); | |
CHECK(c.whole() == 0); | |
CHECK(c.numerator() == 8); | |
CHECK(c.denominator() == 17); | |
CHECK_FALSE(b.isPositive()); | |
} | |
SECTION("Construct from std::string", "Zero denominator") { | |
std::unique_ptr<Fraction> tmp; | |
CHECK_THROWS_AS(tmp.reset(new Fraction{"2/0"}), std::invalid_argument); | |
} | |
} | |
TEST_CASE("Conversion") { | |
SECTION("Proper whole value") { | |
Fraction testvalue{2}; | |
auto oldVal = testvalue.whole(); | |
auto oldNum = testvalue.numerator(); | |
auto oldDenom = testvalue.denominator(); | |
CHECK_FALSE(testvalue.isProper()); | |
testvalue.makeProper(); | |
CHECK(testvalue.whole() == oldVal); | |
CHECK(testvalue.numerator() == oldNum); | |
CHECK(testvalue.denominator() == oldDenom); | |
} | |
SECTION("Always improper") { | |
Fraction a{"3 12/3"}; | |
CHECK_FALSE(a.isProper()); | |
a.makeProper(); | |
CHECK_FALSE(a.isProper()); | |
CHECK(a.whole() == 7); | |
CHECK(a.numerator() == 0); | |
CHECK(a.denominator() == 1); | |
} | |
SECTION("Proper fraction") { | |
Fraction testvalue{"6/13"}; | |
auto oldVal = testvalue.whole(); | |
auto oldNum = testvalue.numerator(); | |
auto oldDenom = testvalue.denominator(); | |
testvalue.makeProper(); | |
CHECK(testvalue.whole() == oldVal); | |
CHECK(testvalue.numerator() == oldNum); | |
CHECK(testvalue.denominator() == oldDenom); | |
CHECK(testvalue.isProper()); | |
} | |
SECTION("Improper fraction") { | |
Fraction testvalue{"37/4"}; | |
auto oldVal = testvalue.whole(); | |
auto oldNum = testvalue.numerator(); | |
auto oldDenom = testvalue.denominator(); | |
CHECK_FALSE(testvalue.isProper()); | |
testvalue.makeProper(); | |
CHECK(testvalue.whole() != oldVal); | |
CHECK(testvalue.whole() == 9); | |
CHECK(testvalue.numerator() != oldNum); | |
CHECK(testvalue.numerator() == 1); | |
CHECK(testvalue.denominator() == oldDenom); | |
} | |
SECTION("makeProper on wholenumber") { | |
Fraction a{51}; | |
a.makeProper(); | |
CHECK(a.whole() == 51); | |
CHECK(a.numerator() == 0); | |
CHECK(a.denominator() == 1); | |
} | |
SECTION("makeproper into whole number") { | |
Fraction testvalue{"36/4"}; | |
testvalue.makeProper(); | |
CHECK(testvalue.whole() == 9); | |
CHECK(testvalue.numerator() == 0); | |
CHECK(testvalue.denominator() == 1); | |
} | |
SECTION("toProper on proper fraction") { | |
Fraction testValue{"13/79"}; | |
Fraction out = testValue.toProper(); | |
CHECK(out.whole() == 0); | |
CHECK(out.numerator() == 13); | |
CHECK(out.denominator() == 79); | |
} | |
SECTION("toProper") { | |
Fraction testValue{"130/12"}; | |
Fraction out = testValue.toProper(); | |
CHECK(out.whole() == 10); | |
CHECK(out.numerator() == 10); | |
CHECK(out.denominator() == 12); | |
} | |
} | |
TEST_CASE("Input") { | |
SECTION("Whole number only") { | |
istringstream source("[0]"); | |
Fraction num; | |
source >> num; | |
CHECK(num.whole() == 0); | |
CHECK(num.numerator() == 0); | |
CHECK(num.denominator() == 1); | |
CHECK(num.isPositive()); | |
} | |
SECTION("Whole number only") { | |
istringstream source("[3]"); | |
Fraction num; | |
source >> num; | |
CHECK(num.whole() == 3); | |
CHECK(num.numerator() == 0); | |
CHECK(num.denominator() == 1); | |
CHECK(num.isPositive()); | |
} | |
SECTION("Negative whole number only") { | |
istringstream source("[-3]"); | |
Fraction num; | |
source >> num; | |
CHECK(num.whole() == 3); | |
CHECK(num.numerator() == 0); | |
CHECK(num.denominator() == 1); | |
CHECK_FALSE(num.isPositive()); | |
} | |
SECTION("Read whole number only among other data") { | |
istringstream source("text [3]234"); | |
Fraction num; | |
string before; | |
int after; | |
source >> before >> num >> after; | |
CHECK(before == "text"); | |
CHECK(after == 234); | |
CHECK(num.whole() == 3); | |
CHECK(num.numerator() == 0); | |
CHECK(num.denominator() == 1); | |
CHECK(num.isPositive()); | |
} | |
SECTION("Fraction only") { | |
istringstream source("[113/219]"); | |
Fraction num; | |
source >> num; | |
CHECK(num.whole() == 0); | |
CHECK(num.numerator() == 113); | |
CHECK(num.denominator() == 219); | |
CHECK(num.isPositive()); | |
} | |
SECTION("Negative Fraction only") { | |
istringstream source("[-113/219]"); | |
Fraction num; | |
source >> num; | |
CHECK(num.whole() == 0); | |
CHECK(num.numerator() == 113); | |
CHECK(num.denominator() == 219); | |
CHECK_FALSE(num.isPositive()); | |
} | |
SECTION("Whole and fraction") { | |
istringstream source("[27 113/219]"); | |
Fraction num; | |
source >> num; | |
CHECK(num.whole() == 27); | |
CHECK(num.numerator() == 113); | |
CHECK(num.denominator() == 219); | |
CHECK(num.isPositive()); | |
} | |
SECTION("Negative Whole and fraction") { | |
istringstream source("[-27 113/219]"); | |
Fraction num; | |
source >> num; | |
CHECK(num.whole() == 27); | |
CHECK(num.numerator() == 113); | |
CHECK(num.denominator() == 219); | |
CHECK_FALSE(num.isPositive()); | |
} | |
SECTION("zero denonimator") { | |
istringstream source("[14/0]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("zero denonimator") { | |
istringstream source("[2 14/0]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
} | |
TEST_CASE("Invalid Input") { | |
SECTION("Whole number missing [") { | |
istringstream source("283]"); // Missing '[' | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Whole number missing ]") { | |
istringstream source("[13"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Whole number missing ], found invalid character") { | |
istringstream source("[13?"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Invalid numerator") { | |
istringstream source("[13 abc/45]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Invalid denominator") { | |
istringstream source("[13 20/abd]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Invalid character after whole number") { | |
istringstream source("[13,5/7]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Invalid character between num/denum") { | |
istringstream source("[13 5#7]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Invalid character at the end") { | |
istringstream source("[13 5/7$"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Non numeric character") { | |
istringstream source("[abcd]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("No numbers") { | |
istringstream source("[]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("No numbers, got invalid character") { | |
istringstream source("[#"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("No numbers only negative sign") { | |
istringstream source("[-]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Negative numerator") { | |
istringstream source("20 -5/17]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
SECTION("Negative denominator") { | |
istringstream source("20 5/-17]"); | |
Fraction num; | |
CHECK_THROWS_AS(source >> num, std::invalid_argument); | |
} | |
} | |
TEST_CASE("Reduction") { | |
SECTION("Verify if fraction is reduced") { | |
Fraction a{"15/35"}; | |
Fraction b{"35/15"}; | |
CHECK_FALSE(a.isReduced()); | |
CHECK_FALSE(b.isReduced()); | |
} | |
SECTION("reduce()") { | |
Fraction a{"270/390"}; | |
a.reduce(); | |
CHECK(a.whole() == 0); | |
CHECK(a.numerator() == 9); | |
CHECK(a.denominator() == 13); | |
} | |
SECTION("reduce() relative prime") { | |
Fraction a{"270/391"}; | |
a.reduce(); | |
CHECK(a.isReduced()); | |
CHECK(a.whole() == 0); | |
CHECK(a.numerator() == 270); | |
CHECK(a.denominator() == 391); | |
} | |
SECTION("toReduced() relative prime") { | |
Fraction a{"270/390"}; | |
Fraction b = a.toReduced(); | |
CHECK(b.whole() == 0); | |
CHECK(b.numerator() == 9); | |
CHECK(b.denominator() == 13); | |
} | |
SECTION("Reduction big number") { | |
Fraction a{"13 400/1000"}; | |
a.reduce(); | |
CHECK(a.isPositive()); | |
CHECK(a.whole() == 13); | |
CHECK(a.numerator() == 2); | |
CHECK(a.denominator() == 5); | |
} | |
SECTION("Reduction big number (negative)") { | |
Fraction a{"-13 400/1000"}; | |
a.reduce(); | |
CHECK_FALSE(a.isPositive()); | |
CHECK(a.whole() == 13); | |
CHECK(a.numerator() == 2); | |
CHECK(a.denominator() == 5); | |
} | |
} | |
TEST_CASE("Output") { | |
SECTION("zero") { | |
Fraction x; | |
ostringstream out; | |
out << x; | |
CHECK(out.str() == "[0]"); | |
} | |
SECTION("positive whole number") { | |
Fraction x{3}; | |
ostringstream out; | |
out << x; | |
CHECK(out.str() == "[3]"); | |
} | |
SECTION("positive fraction only") { | |
Fraction x{"7/19"}; | |
ostringstream out; | |
out << x; | |
CHECK(out.str() == "[7/19]"); | |
} | |
SECTION("positive whole and fraction") { | |
Fraction x{"5 8/19"}; | |
ostringstream out; | |
out << x; | |
CHECK(out.str() == "[5 8/19]"); | |
} | |
SECTION("Negative whole number") { | |
Fraction x{-3}; | |
ostringstream out; | |
out << x; | |
CHECK(out.str() == "[-3]"); | |
} | |
SECTION("Negative whole and fraction") { | |
Fraction x{"-5 8/19"}; | |
ostringstream out; | |
out << x; | |
CHECK(out.str() == "[-5 8/19]"); | |
} | |
SECTION("Negative fraction only") { | |
Fraction x{"-7/19"}; | |
ostringstream out; | |
out << x; | |
CHECK(out.str() == "[-7/19]"); | |
} | |
} | |
TEST_CASE("Operator Assignment") { | |
SECTION("Move Assignment") { | |
Fraction one{"-3 7/19"}; | |
Fraction two; | |
two = std::move(one); | |
CHECK(two.whole() == 3); | |
CHECK_FALSE(two.isPositive()); | |
CHECK(two.numerator() == 7); | |
CHECK(two.denominator() == 19); | |
} | |
SECTION("Copy Assignment") { | |
Fraction one{"-8 6/19"}; | |
Fraction two; | |
two = one; | |
CHECK(two.whole() == 8); | |
CHECK_FALSE(two.isPositive()); | |
CHECK(two.numerator() == 6); | |
CHECK(two.denominator() == 19); | |
} | |
} | |
TEST_CASE("Operator +") { | |
SECTION("Fraction as first operand") { | |
Fraction one{"2 6/13"}; | |
Fraction sum; | |
sum = one + 5; | |
CHECK(sum.whole() == 7); | |
CHECK(sum.numerator() == 6); | |
CHECK(sum.denominator() == 13); | |
CHECK(sum.isPositive()); | |
} | |
SECTION("Fraction as second operand") { | |
Fraction one{"2 6/13"}; | |
Fraction sum; | |
sum = 15 + one; | |
CHECK(sum.whole() == 17); | |
CHECK(sum.numerator() == 6); | |
CHECK(sum.denominator() == 13); | |
CHECK(sum.isPositive()); | |
} | |
SECTION("With negative number and fraction as second operand") { | |
Fraction one{"2 6/13"}; | |
Fraction sum; | |
sum = -14 + one; // -11 7/13 | |
CHECK(sum.whole() == 11); | |
CHECK(sum.numerator() == 7); | |
CHECK(sum.denominator() == 13); | |
CHECK_FALSE(sum.isPositive()); | |
} | |
SECTION("Add two positive fractions") { | |
Fraction a{"21 5/6"}; | |
Fraction b{"9 3/4"}; | |
Fraction sum = a + b; // 21 10/12 + 9 9/12 = 30 19/12 = 31 7/12 | |
CHECK(sum.isPositive()); | |
CHECK(sum.whole() == 31); | |
CHECK(sum.numerator() == 7); | |
CHECK(sum.denominator() == 12); | |
} | |
SECTION("Add two negative fractions") { | |
Fraction a{"-17 5/8"}; | |
Fraction b{"-3 3/14"}; | |
Fraction sum = a + b; // -17 35/56 - 3 12/56 = -20 47/56 | |
CHECK_FALSE(sum.isPositive()); | |
CHECK(sum.whole() == 20); | |
CHECK(sum.numerator() == 47); | |
CHECK(sum.denominator() == 56); | |
} | |
SECTION("Add two fractions with different sign, negative result") { | |
Fraction a{"-10 5/7"}; | |
Fraction b{"5 3/14"}; | |
Fraction sum = a + b; // -10 10/14 + 5 3/14 = | |
CHECK_FALSE(sum.isPositive()); | |
CHECK(sum.whole() == 5); | |
CHECK(sum.numerator() == 1); | |
CHECK(sum.denominator() == 2); | |
} | |
SECTION("Add two fractions with different sign, positive result") { | |
Fraction a{"11 5/7"}; | |
Fraction b{"-9 3/14"}; | |
Fraction sum = a + b; | |
CHECK(sum.isPositive()); | |
CHECK(sum.whole() == 2); | |
CHECK(sum.numerator() == 1); | |
CHECK(sum.denominator() == 2); | |
} | |
} | |
TEST_CASE("Operator -") { | |
SECTION("Fraction as first operand") { | |
Fraction one{"2 6/13"}; | |
Fraction sum; | |
sum = one - 5; | |
CHECK(sum.whole() == 2); | |
CHECK(sum.numerator() == 7); | |
CHECK(sum.denominator() == 13); | |
CHECK_FALSE(sum.isPositive()); | |
} | |
SECTION("Fraction as second operand") { | |
Fraction one{"2 6/13"}; | |
Fraction sum; | |
sum = 15 - one; | |
CHECK(sum.whole() == 12); | |
CHECK(sum.numerator() == 7); | |
CHECK(sum.denominator() == 13); | |
CHECK(sum.isPositive()); | |
} | |
SECTION("Subtract two positive fractions. positive result") { | |
Fraction a{"33 5/6"}; | |
Fraction b{"9 3/4"}; | |
Fraction sum = a - b; // 33 10/12 - 9 9/12 = 33 19/12 = 24 1/12 | |
CHECK(sum.isPositive()); | |
CHECK(sum.whole() == 24); | |
CHECK(sum.numerator() == 1); | |
CHECK(sum.denominator() == 12); | |
} | |
SECTION("Subtract two positive fractions. negative result") { | |
Fraction a{"33 5/6"}; | |
Fraction b{"9 3/4"}; | |
Fraction sum; | |
sum = b - a; // -33 10/12 + 9 9/12 = -33 19/12 = -24 1/12 | |
CHECK_FALSE(sum.isPositive()); | |
CHECK(sum.whole() == 24); | |
CHECK(sum.numerator() == 1); | |
CHECK(sum.denominator() == 12); | |
} | |
SECTION("Subtract two negative fractions") { | |
Fraction a{"-17 5/8"}; | |
Fraction b{"-3 3/14"}; | |
Fraction sum; | |
sum = a - b; // -17 35/56 + 3 12/56 = -14 23/56 | |
CHECK_FALSE(sum.isPositive()); | |
CHECK(sum.whole() == 14); | |
CHECK(sum.numerator() == 23); | |
CHECK(sum.denominator() == 56); | |
} | |
SECTION("Subtract to zero") { | |
Fraction one{"4 17/30"}; | |
Fraction zero; | |
zero = one - one; | |
CHECK(zero.isPositive()); | |
CHECK(zero.whole() == 0); | |
CHECK(zero.numerator() == 0); | |
CHECK(zero.denominator() == 1); | |
} | |
} | |
TEST_CASE("Operator - (unary)") { | |
SECTION("Flip positive whole number") { | |
Fraction a{"517"}; | |
Fraction b; | |
b = -a; | |
CHECK_FALSE(b.isPositive()); | |
CHECK(b.whole() == 517); | |
CHECK(b.numerator() == 0); | |
CHECK(b.denominator() == 1); | |
} | |
SECTION("Flip negative whole number") { | |
Fraction a{"-517"}; | |
Fraction b; | |
b = -a; | |
CHECK(b.isPositive()); | |
CHECK(b.whole() == 517); | |
CHECK(b.numerator() == 0); | |
CHECK(b.denominator() == 1); | |
} | |
SECTION("Flip positive fraction only") { | |
Fraction a{"51/73"}; | |
Fraction b; | |
b = -a; | |
CHECK_FALSE(b.isPositive()); | |
CHECK(b.whole() == 0); | |
CHECK(b.numerator() == 51); | |
CHECK(b.denominator() == 73); | |
} | |
SECTION("Flip negative fraction only") { | |
Fraction a{"-51/73"}; | |
Fraction b; | |
b = -a; | |
CHECK(b.isPositive()); | |
CHECK(b.whole() == 0); | |
CHECK(b.numerator() == 51); | |
CHECK(b.denominator() == 73); | |
} | |
SECTION("Flip positive mixed fraction") { | |
Fraction a{"23 51/73"}; | |
Fraction b; | |
b = -a; | |
CHECK_FALSE(b.isPositive()); | |
CHECK(b.whole() == 23); | |
CHECK(b.numerator() == 51); | |
CHECK(b.denominator() == 73); | |
} | |
SECTION("Flip positive mixed fraction") { | |
Fraction a{"-23 51/73"}; | |
Fraction b; | |
b = -a; | |
CHECK(b.isPositive()); | |
CHECK(b.whole() == 23); | |
CHECK(b.numerator() == 51); | |
CHECK(b.denominator() == 73); | |
} | |
} | |
TEST_CASE("Multiplication") { | |
SECTION("Multiplication with scalar on right") { | |
Fraction one{"2 9/15"}; | |
Fraction prod; | |
prod = one * 4; | |
CHECK(prod.isPositive()); | |
CHECK(prod.whole() == 10); | |
CHECK(prod.numerator() == 2); | |
CHECK(prod.denominator() == 5); | |
} | |
SECTION("Multiplication with scalar on left") { | |
Fraction one{"2 9/15"}; | |
Fraction prod; | |
prod = 4 * one; | |
CHECK(prod.isPositive()); | |
CHECK(prod.whole() == 10); | |
CHECK(prod.numerator() == 2); | |
CHECK(prod.denominator() == 5); | |
} | |
SECTION("Multiplication with zero on left") { | |
Fraction one{"2 9/15"}; | |
Fraction prod; | |
prod = 0 * one; | |
CHECK(prod.isPositive()); | |
CHECK(prod.whole() == 0); | |
CHECK(prod.numerator() == 0); | |
CHECK(prod.denominator() == 1); | |
} | |
SECTION("Multiplication with zero on right") { | |
Fraction one{"2 9/15"}; | |
Fraction prod; | |
prod = one * 0; | |
CHECK(prod.isPositive()); | |
CHECK(prod.whole() == 0); | |
CHECK(prod.numerator() == 0); | |
CHECK(prod.denominator() == 1); | |
} | |
SECTION("Multiplication with -1") { | |
Fraction one{"2 9/15"}; | |
Fraction prod; | |
prod = one * -1; | |
CHECK_FALSE(prod.isPositive()); | |
CHECK(prod.whole() == 2); | |
CHECK(prod.numerator() == 3); | |
CHECK(prod.denominator() == 5); | |
} | |
SECTION("Multiply two positive fractions") { | |
Fraction one{"3 7/11"}; | |
Fraction two{"5 8/9"}; | |
Fraction prod; | |
prod = one * two; | |
CHECK(prod.isPositive()); | |
CHECK(prod.whole() == 21); | |
CHECK(prod.numerator() == 41); | |
CHECK(prod.denominator() == 99); | |
} | |
SECTION("Multiply two negative fractions") { | |
Fraction one{"-3 7/11"}; | |
Fraction two{"-5 8/9"}; | |
Fraction prod; | |
prod = one * two; | |
CHECK(prod.isPositive()); | |
CHECK(prod.whole() == 21); | |
CHECK(prod.numerator() == 41); | |
CHECK(prod.denominator() == 99); | |
} | |
SECTION("Multiply two fractions of different sign") { | |
Fraction one{"3 7/11"}; | |
Fraction two{"-5 8/9"}; | |
Fraction prod; | |
prod = one * two; | |
CHECK_FALSE(prod.isPositive()); | |
CHECK(prod.whole() == 21); | |
CHECK(prod.numerator() == 41); | |
CHECK(prod.denominator() == 99); | |
} | |
} | |
TEST_CASE("Operator[]") { | |
SECTION("Positive whole number") { | |
Fraction a{"4"}; | |
CHECK(a[0].has_value()); | |
CHECK(a[0] == 4); | |
CHECK_FALSE(a[1].has_value()); | |
CHECK_FALSE(a[2].has_value()); | |
} | |
SECTION("Positive fraction") { | |
Fraction a{"4/19"}; | |
CHECK_FALSE(a[0].has_value()); | |
CHECK(a[1].has_value()); | |
CHECK(a[1] == 4); | |
CHECK(a[2].has_value()); | |
CHECK(a[2] == 19); | |
} | |
SECTION("Positive mixed fraction") { | |
Fraction a{"21 4/19"}; | |
INFO("Tested fraction 21 4/19"); | |
CHECK(a[0].has_value()); | |
CHECK(a[0] == 21); | |
CHECK(a[1].has_value()); | |
CHECK(a[1] == 4); | |
CHECK(a[2].has_value()); | |
CHECK(a[2] == 19); | |
} | |
SECTION("Negative whole number") { | |
Fraction a{"-4"}; | |
CHECK(a[0].has_value()); | |
CHECK(a[0] == -4); | |
CHECK_FALSE(a[1].has_value()); | |
CHECK_FALSE(a[2].has_value()); | |
} | |
SECTION("Negative fraction") { | |
Fraction a{"-4/19"}; | |
INFO("Tested fraction -4/19"); | |
CHECK_FALSE(a[0].has_value()); | |
CHECK(a[1].has_value()); | |
CHECK(a[1] == -4); | |
CHECK(a[2].has_value()); | |
CHECK(a[2] == 19); | |
} | |
SECTION("Positive mixed fraction") { | |
Fraction a{"-21 4/19"}; | |
INFO("Tested fraction -21 4/19"); | |
CHECK(a[0].has_value()); | |
CHECK(a[0] == -21); | |
CHECK(a[1].has_value()); | |
CHECK(a[1] == 4); | |
CHECK(a[2].has_value()); | |
CHECK(a[2] == 19); | |
} | |
} | |
TEST_CASE("Arithmetic result must be proper and reduced") { | |
SECTION("Add two fractions with reduced result") { | |
Fraction a{"5 3/40"}; | |
Fraction b{"9 27/40"}; | |
a = a + b; | |
CHECK(a.isPositive()); | |
CHECK(a.whole() == 14); | |
CHECK(a.numerator() == 3); | |
CHECK(a.denominator() == 4); | |
} | |
SECTION("Multiple two fractions with who result") { | |
Fraction a{"-3/40"}; | |
Fraction b{"40/3"}; | |
a = a * b; | |
CHECK_FALSE(a.isPositive()); | |
CHECK(a.whole() == 1); | |
CHECK(a.numerator() == 0); | |
CHECK(a.denominator() == 1); | |
} | |
SECTION("Multiply with int") { | |
Fraction a{"6 4/7"}; | |
a = a * 7; | |
CHECK(a.isPositive()); | |
CHECK(a.whole() == 46); | |
CHECK(a.numerator() == 0); | |
CHECK(a.denominator() == 1); | |
} | |
SECTION("Multiply two fractions") { | |
Fraction a{"2/5"}; | |
Fraction b{"5 1/3"}; | |
a = a * b; | |
CHECK(a.isPositive()); | |
CHECK(a.whole() == 2); | |
CHECK(a.numerator() == 2); | |
CHECK(a.denominator() == 15); | |
} | |
} | |
TEST_CASE("operator==") { | |
SECTION("Different sign") { | |
Fraction a{"-4 7/8"}; | |
Fraction b{"6 3/10"}; | |
CHECK_FALSE(a == b); | |
} | |
SECTION("Positive fractions: equal") { | |
Fraction a{"4 7/8"}; | |
Fraction b{"4 77/88"}; | |
CHECK(a == b); | |
} | |
SECTION("Negative fractions: equal") { | |
Fraction a{"-4 7/8"}; | |
Fraction b{"-4 91/104"}; | |
CHECK(a == b); | |
} | |
SECTION("Positive fractions: not equal") { | |
Fraction a{"4 7/8"}; | |
Fraction b{"4 74/88"}; | |
CHECK_FALSE(a == b); | |
} | |
SECTION("Negative fractions: not equal") { | |
Fraction a{"-33 5/8"}; | |
Fraction b{"-33 74/88"}; | |
CHECK_FALSE(a == b); | |
} | |
} | |
TEST_CASE("Operator<") { | |
SECTION("Different sign") { | |
Fraction a{"-10 5/7"}; | |
Fraction b{"3 17/20"}; | |
CHECK(a < b); | |
CHECK_FALSE(b < a); | |
} | |
SECTION("Both positive") { | |
Fraction a{"10 5/7"}; | |
Fraction b{"3 17/20"}; | |
CHECK_FALSE(a < b); | |
CHECK(b < a); | |
} | |
SECTION("Both negative: mixed and fraction") { | |
Fraction a{"-5/6"}; | |
Fraction b{"-1 17/20"}; | |
CHECK_FALSE(a < b); | |
CHECK(b < a); | |
} | |
SECTION("Both positive: mixed and fraction only") { | |
Fraction a{"15/3"}; | |
Fraction b{"1 20/20"}; | |
CHECK_FALSE(a < b); | |
CHECK(b < a); | |
} | |
} | |
TEST_CASE("Fraction arithmetic") { | |
Fraction one{"3 12/25"}; | |
Fraction two{"11 4/5"}; | |
Fraction result; | |
result = one + two - two * one; | |
CHECK_FALSE(result.isPositive()); | |
CHECK(result.whole() == 25); | |
CHECK(result.numerator() == 98); | |
CHECK(result.denominator() == 125); | |
} | |
#if I_DO_EXTRA_CREDIT | |
TEST_CASE("Repeating Fraction") { | |
std::map<int, string> repeating; | |
repeating[3] = "0.3"; | |
repeating[6] = "0.16"; | |
repeating[7] = "0.142857"; | |
repeating[9] = "0.1"; | |
repeating[11] = "0.09"; | |
repeating[12] = "0.083"; | |
repeating[13] = "0.076923"; | |
repeating[14] = "0.0714285"; | |
repeating[15] = "0.06"; | |
repeating[17] = "0.0588235294117647"; | |
repeating[18] = "0.05"; | |
repeating[19] = "0.052631578947368421"; | |
optional<string> out; | |
for (int k = 2; k < 20; k++) { | |
Fraction a{"1/" + std::to_string(k)}; | |
out = a.isRepeating(); | |
auto r = repeating.find(k); | |
if (r != repeating.end()) { | |
CHECK(out.has_value()); | |
CHECK(r->second == *out); | |
} else { | |
CHECK_FALSE(out.has_value()); | |
} | |
} | |
} | |
TEST_CASE("Operator()") { | |
SECTION("Positive mixed") { | |
Fraction a{"123 1/2"}; | |
CHECK(a(2) == "124"); | |
CHECK(a(3) == "124"); | |
CHECK(a(4) == "124."); | |
CHECK(a(5) == "123.5"); | |
CHECK(a(6) == "123.50"); | |
CHECK(a(7) == "123.500"); | |
} | |
SECTION("Negative mixed") { | |
Fraction a{"-123 1/2"}; | |
CHECK(a(2) == "-124"); | |
CHECK(a(3) == "-124"); | |
CHECK(a(4) == "-124"); | |
CHECK(a(5) == "-124."); | |
CHECK(a(6) == "-123.5"); | |
CHECK(a(7) == "-123.50"); | |
CHECK(a(8) == "-123.500"); | |
} | |
SECTION("Positive repeating") { | |
Fraction a{"10 2/3"}; | |
CHECK(a(1) == "11"); | |
CHECK(a(2) == "11"); | |
CHECK(a(3) == "11."); | |
CHECK(a(4) == "10.7"); | |
CHECK(a(5) == "10.67"); | |
CHECK(a(6) == "10.667"); | |
CHECK(a(7) == "10.6667"); | |
} | |
SECTION("Negative repeating") { | |
Fraction a{"-10 2/3"}; | |
CHECK(a(1) == "-11"); | |
CHECK(a(2) == "-11"); | |
CHECK(a(3) == "-11"); | |
CHECK(a(4) == "-11."); | |
CHECK(a(5) == "-10.7"); | |
CHECK(a(6) == "-10.67"); | |
CHECK(a(7) == "-10.667"); | |
} | |
SECTION("Positive repeating fration only") { | |
Fraction a{"2/3"}; | |
CHECK(a(1) == ".7"); | |
CHECK(a(2) == ".7"); | |
CHECK(a(3) == ".67"); | |
CHECK(a(4) == ".667"); | |
CHECK(a(5) == ".6667"); | |
} | |
SECTION("Positive repeating fraction only") { | |
Fraction a{"1/7"}; | |
// 0.142857 | |
CHECK(a(1) == ".1"); | |
CHECK(a(2) == ".1"); | |
CHECK(a(3) == ".14"); | |
CHECK(a(4) == ".143"); | |
CHECK(a(5) == ".1429"); | |
CHECK(a(6) == ".14286"); | |
CHECK(a(7) == ".142857"); | |
CHECK(a(8) == ".1428571"); | |
CHECK(a(9) == ".14285714"); | |
CHECK(a(10) == ".142857143"); | |
CHECK(a(11) == ".1428571429"); | |
CHECK(a(12) == ".14285714286"); | |
CHECK(a(13) == ".142857142857"); | |
} | |
SECTION("Zero") { | |
Fraction zero; | |
for (int k = 1; k < 20; k++) | |
CHECK(zero(k) == "0"); | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment