From 87759391d884e61d1151029432f382959ff4c0bc Mon Sep 17 00:00:00 2001 From: Tobias Berger Date: Tue, 21 Sep 2021 11:42:53 +0200 Subject: [PATCH] pow --- fraction.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- fraction.hpp | 7 +++++++ tst_fractiontest.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/fraction.cpp b/fraction.cpp index 44dd38a..ea1e5fe 100644 --- a/fraction.cpp +++ b/fraction.cpp @@ -1,7 +1,8 @@ #include "fraction.hpp" -namespace FractionNS { +#include +namespace FractionNS { int gcd(int p, int q) { if(p < 0) p = -p; if(q < 0) q = -q; @@ -270,6 +271,44 @@ namespace FractionNS { return *this; } + double Fraction::pow(const int n) const { + if(n == 0) { + if(m_numerator == 0) { + throw not_defined_error(); + } + return 1.0; + } + if(n < 0) { + if(m_numerator == 0) { + throw not_real_error(); + } + if(n == -1) { + return double(m_denominator) / m_numerator; + } + + return qPow(double(m_denominator) / m_numerator, -n); + } + return qPow(double(m_numerator) / m_denominator, n); + } + double Fraction::pow(const Fraction& other) const { + if(other == 0) { + if(m_numerator == 0) { + throw not_defined_error(); + } + return 1.0; + } + if(other < 0) { + if(m_numerator == 0) { + throw not_real_error(); + } + if(other == -1) { + return double(m_denominator) / m_numerator; + } + return qPow(double(m_denominator) / m_numerator, -other.toDouble()); + } + return qPow(double(m_numerator) / m_denominator, other.toDouble()); + } + Fraction& Fraction::operator-() const { return *new Fraction(-m_numerator, m_denominator); } diff --git a/fraction.hpp b/fraction.hpp index 6f6dcb1..91c169b 100644 --- a/fraction.hpp +++ b/fraction.hpp @@ -86,6 +86,13 @@ namespace FractionNS { Fraction& operator/=(const int); Fraction& operator/=(const Fraction&); + // Maybe replace with ^ operator, as it's unused for this class. + // Might be syntactically not-so-nice though? + // Python uses / for combining paths, does cpp do something similar anywhere? + // How does one raise a Fraction to a power while keeping it a Fraction (avoid double return type) + double pow(const int) const; + double pow(const Fraction&) const; + // Unary operators Fraction& operator-() const; Fraction& operator+() const; // Should return a copy of the Fraction. diff --git a/tst_fractiontest.cpp b/tst_fractiontest.cpp index 228f174..16a3aed 100644 --- a/tst_fractiontest.cpp +++ b/tst_fractiontest.cpp @@ -29,6 +29,7 @@ private slots: void test_less_than_or_equal(); void test_greater_than_or_equal(); void test_inverse(); + void test_pow(); }; FractionTest::FractionTest() { @@ -442,6 +443,46 @@ void FractionTest::test_inverse() { QVERIFY(threw_divide_by_zero_error); } +void FractionTest::test_pow() { + const Fraction f1 = Fraction(2, 3); + const Fraction f2 = Fraction(3, 2); + const Fraction f3 = Fraction(4, 9); + const Fraction f4 = Fraction(9, 4); + + QCOMPARE(f3, f1.pow(2)); + QCOMPARE(f4, f2.pow(2)); + + const Fraction f5 = Fraction(9); + const Fraction f6 = Fraction(1, 9); + const Fraction f7 = Fraction(1, 81); + // x ** -y = (1 / x) ** y + QCOMPARE(f6, f5.pow(-1)); + QCOMPARE(f7, f5.pow(-2)); + + const Fraction f8 = Fraction(16); + // x ** (1/y) = root_y(x) + QCOMPARE(f8.pow(Fraction(1, 2)), 4.0); + + // x ** 0 = 1; (where x != 0 and x ∈ R) + // 0 ** 0 depends on context + QCOMPARE(f1.pow(0), 1.0); + bool threw_correct_error = false; + try { + Fraction(0, 2).pow(0); + } catch (const not_defined_error&) { + threw_correct_error = true; + } + QVERIFY(threw_correct_error); + + threw_correct_error = false; + try { + Fraction(0, 1).pow(-1); + } catch (const not_real_error&) { + threw_correct_error = true; + } + QVERIFY(threw_correct_error); +} + QTEST_APPLESS_MAIN(FractionTest) #include "tst_fractiontest.moc"