]> git.localhorst.tv Git - l2e.git/commitdiff
added Rational template (for fractions)
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 21 Feb 2013 07:10:47 +0000 (08:10 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 24 Feb 2013 21:33:41 +0000 (22:33 +0100)
src/math/Rational.h [new file with mode: 0644]
tests/math/RationalTest.cpp [new file with mode: 0644]
tests/math/RationalTest.h [new file with mode: 0644]

diff --git a/src/math/Rational.h b/src/math/Rational.h
new file mode 100644 (file)
index 0000000..f4b6620
--- /dev/null
@@ -0,0 +1,379 @@
+#ifndef MATH_RATIONAL_H_
+#define MATH_RATIONAL_H_
+
+#include <ostream>
+
+
+namespace math {
+
+/// Rational number type.
+/// Stores 2 Integers and has the value num / denom.
+template<class Integer>
+class Rational {
+
+public:
+       explicit Rational(Integer num = 0, Integer denom = 1)
+       : num(num), denom(denom) { }
+       template<class OtherInt>
+       explicit Rational(const Rational<OtherInt> &other)
+       : num(other.Numerator()), denom(other.Denominator()) { }
+
+public:
+       Integer &Numerator() { return num; }
+       const Integer &Numerator() const { return num; }
+       Integer &Denominator() { return denom; }
+       const Integer &Denominator() const { return denom; }
+
+       Integer Int() const { return num / denom; }
+       Integer Inv() const { return denom / num; }
+       float Float() const { return float(num) / denom; }
+       double Double() const { return double(num) / denom; }
+
+       bool IsWhole() const {
+               return num % denom == 0;
+       }
+       bool IsFrac() const {
+               return num % denom != 0;
+       }
+
+       void QuickPack() {
+               if (num == 1 || denom == 1) return;
+               if (num % denom == 0) {
+                       num /= denom;
+                       denom = 1;
+               } else if (denom % num == 0) {
+                       denom /= num;
+                       num = 1;
+               }
+       }
+
+       void Pack() {
+               if (num == 1 || denom == 1) return;
+               if (num % denom == 0) {
+                       num /= denom;
+                       denom = 1;
+                       return;
+               }
+               if (denom % num == 0) {
+                       denom /= num;
+                       num = 1;
+                       return;
+               }
+               while (num % 2 == 0 && denom % 2 == 0) {
+                       num /= 2;
+                       denom /= 2;
+               }
+               while (num % 3 == 0 && denom % 3 == 0) {
+                       num /= 3;
+                       denom /= 3;
+               }
+               while (num % 5 == 0 && denom % 5 == 0) {
+                       num /= 5;
+                       denom /= 5;
+               }
+       }
+
+public:
+       template<class OtherInt>
+       Rational &operator =(OtherInt i) {
+               num = i;
+               denom = 1;
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator =(Rational<OtherInt> r) {
+               num = r.Numerator();
+               denom = r.Denominator();
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator +=(OtherInt i) {
+               num += i * denom;
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator +=(Rational<OtherInt> r) {
+               num = num * r.Denominator() + r.Numerator() * denom;
+               denom *= r.Denominator();
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator -=(OtherInt i) {
+               num -= i * denom;
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator -=(Rational<OtherInt> r) {
+               num = num * r.Denominator() - r.Numerator() * denom;
+               denom *= r.Denominator();
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator *=(OtherInt i) {
+               if (denom % i == 0) {
+                       denom /= i;
+               } else {
+                       num *= i;
+               }
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator *=(const Rational<OtherInt> &r) {
+               num *= r.Numerator();
+               denom *= r.Denominator();
+               return *this;
+       }
+       Rational &operator *=(float f) {
+               num *= f;
+               return *this;
+       }
+       Rational &operator *=(double d) {
+               num *= d;
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator /=(OtherInt i) {
+               if (num % i == 0) {
+                       num /= i;
+               } else {
+                       denom *= i;
+               }
+               return *this;
+       }
+       template<class OtherInt>
+       Rational &operator /=(const Rational<OtherInt> &r) {
+               num *= r.Denominator();
+               denom *= r.Numerator();
+               return *this;
+       }
+       Rational &operator /=(float f) {
+               if (f > 1 || f < -1) {
+                       denom *= f;
+               } else {
+                       num /= f;
+               }
+               return *this;
+       }
+       Rational &operator /=(double d) {
+               if (d > 1 || d < -1) {
+                       denom *= d;
+               } else {
+                       num /= d;
+               }
+               return *this;
+       }
+
+private:
+       Integer num;
+       Integer denom;
+
+};
+
+template<class Integer>
+Rational<Integer> operator -(const Rational<Integer> &r) {
+       return Rational<Integer>(-r.Numerator(), r.Denominator());
+}
+
+template<class LInt, class RInt>
+bool operator ==(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return lhs.Numerator() * rhs.Denominator() ==
+                       rhs.Numerator() * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator !=(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return !(lhs == rhs);
+}
+template<class LInt, class RInt>
+bool operator ==(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return lhs.IsWhole() && lhs.Int() == rhs;
+}
+template<class LInt, class RInt>
+bool operator !=(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return !(lhs == rhs);
+}
+template<class LInt, class RInt>
+bool operator ==(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return rhs == lhs;
+}
+template<class LInt, class RInt>
+bool operator !=(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return rhs != lhs;
+}
+
+template<class LInt, class RInt>
+bool operator <(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return lhs.Numerator() * rhs.Denominator() <
+                       rhs.Numerator() * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator <(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return lhs.Numerator() < rhs * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator <(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return lhs * rhs.Denominator() < rhs.Numerator();
+}
+
+template<class LInt, class RInt>
+bool operator <=(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return lhs.Numerator() * rhs.Denominator() <=
+                       rhs.Numerator() * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator <=(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return lhs.Numerator() <= rhs * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator <=(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return lhs * rhs.Denominator() <= rhs.Numerator();
+}
+
+template<class LInt, class RInt>
+bool operator >(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return lhs.Numerator() * rhs.Denominator() >
+                       rhs.Numerator() * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator >(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return lhs.Numerator() > rhs * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator >(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return lhs * rhs.Denominator() > rhs.Numerator();
+}
+
+template<class LInt, class RInt>
+bool operator >=(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return lhs.Numerator() * rhs.Denominator() >=
+                       rhs.Numerator() * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator >=(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return lhs.Numerator() >= rhs * lhs.Denominator();
+}
+template<class LInt, class RInt>
+bool operator >=(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return lhs * rhs.Denominator() >= rhs.Numerator();
+}
+
+template<class LInt, class RInt>
+Rational<LInt> operator +(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return Rational<LInt>(lhs) += rhs;
+}
+template<class LInt, class RInt>
+Rational<LInt> operator +(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return Rational<LInt>(lhs) += rhs;
+}
+template<class LInt, class RInt>
+LInt operator +(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return lhs + rhs.Int();
+}
+
+template<class LInt, class RInt>
+Rational<LInt> operator -(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return Rational<LInt>(lhs) -= rhs;
+}
+template<class LInt, class RInt>
+Rational<LInt> operator -(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return Rational<LInt>(lhs) -= rhs;
+}
+template<class LInt, class RInt>
+LInt operator -(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return lhs - rhs.Int();
+}
+
+template<class LInt, class RInt>
+Rational<LInt> operator *(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return Rational<LInt>(lhs) *= rhs;
+}
+template<class LInt, class RInt>
+Rational<LInt> operator *(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return Rational<LInt>(lhs) *= rhs;
+}
+template<class LInt, class RInt>
+LInt operator *(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return lhs * rhs.Numerator() / rhs.Denominator();
+}
+
+template<class LInt, class RInt>
+Rational<LInt> operator /(
+               const Rational<LInt> &lhs,
+               const Rational<RInt> &rhs) {
+       return Rational<LInt>(lhs) /= rhs;
+}
+template<class LInt, class RInt>
+Rational<LInt> operator /(
+               const Rational<LInt> &lhs,
+               RInt rhs) {
+       return Rational<LInt>(lhs) /= rhs;
+}
+template<class LInt, class RInt>
+LInt operator /(
+               LInt lhs,
+               const Rational<RInt> &rhs) {
+       return lhs * rhs.Denominator() / rhs.Numerator();
+}
+
+
+template<class Integer>
+inline std::ostream &operator <<(std::ostream &out, const Rational<Integer> &r) {
+       return out << r.Double();
+}
+
+}
+
+#endif
diff --git a/tests/math/RationalTest.cpp b/tests/math/RationalTest.cpp
new file mode 100644 (file)
index 0000000..d2a531a
--- /dev/null
@@ -0,0 +1,95 @@
+#include "RationalTest.h"
+
+#include <SDL.h>
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test_math::RationalTest);
+
+typedef math::Rational<int> Rational;
+typedef math::Rational<short> ShortRational;
+
+
+namespace test_math {
+
+void RationalTest::setUp() {
+
+}
+
+void RationalTest::tearDown() {
+
+}
+
+
+void RationalTest::testConversion() {
+       CPPUNIT_ASSERT_EQUAL(1, Rational(3, 2).Int());
+       CPPUNIT_ASSERT_DOUBLES_EQUAL(0.75, Rational(3, 4).Double(), std::numeric_limits<double>::epsilon());
+
+       CPPUNIT_ASSERT_EQUAL(-1, Rational(-3, 2).Int());
+       CPPUNIT_ASSERT_EQUAL(Rational(3, 2), Rational(ShortRational(3, 2)));
+       CPPUNIT_ASSERT_EQUAL(ShortRational(3, 2), ShortRational(Rational(3, 2)));
+}
+
+void RationalTest::testComparison() {
+       CPPUNIT_ASSERT_EQUAL(Rational(), Rational());
+       CPPUNIT_ASSERT_EQUAL(Rational(1), Rational(1));
+       CPPUNIT_ASSERT_EQUAL(Rational(-1), Rational(-1));
+
+       CPPUNIT_ASSERT_EQUAL(Rational(1, 2), Rational(2, 4));
+
+       CPPUNIT_ASSERT(Rational(0) != Rational(1));
+       CPPUNIT_ASSERT(Rational(0) != Rational(-1));
+       CPPUNIT_ASSERT(Rational(1, 2) != Rational(-1, 2));
+
+       CPPUNIT_ASSERT(Rational(0) < Rational(1));
+       CPPUNIT_ASSERT(Rational(1, 2) <= Rational(1));
+       CPPUNIT_ASSERT(Rational(0) > Rational(-1));
+       CPPUNIT_ASSERT(Rational(1) >= Rational(-1, 2));
+
+       CPPUNIT_ASSERT(Rational() == ShortRational());
+       CPPUNIT_ASSERT(ShortRational() == Rational());
+       CPPUNIT_ASSERT(Rational(1) == ShortRational(1));
+       CPPUNIT_ASSERT(ShortRational(1) == Rational(1));
+       CPPUNIT_ASSERT(Rational(-1) == ShortRational(-1));
+       CPPUNIT_ASSERT(ShortRational(-1) == Rational(-1));
+
+       CPPUNIT_ASSERT(Rational(1, 2) == ShortRational(2, 4));
+       CPPUNIT_ASSERT(ShortRational(1, 2) == Rational(2, 4));
+
+       CPPUNIT_ASSERT(Rational(0) != ShortRational(1));
+       CPPUNIT_ASSERT(ShortRational(0) != Rational(1));
+       CPPUNIT_ASSERT(Rational(0) != ShortRational(-1));
+       CPPUNIT_ASSERT(ShortRational(0) != Rational(-1));
+       CPPUNIT_ASSERT(Rational(1, 2) != ShortRational(-1, 2));
+       CPPUNIT_ASSERT(ShortRational(1, 2) != Rational(-1, 2));
+
+       CPPUNIT_ASSERT(Rational(0) < ShortRational(1));
+       CPPUNIT_ASSERT(ShortRational(0) < Rational(1));
+       CPPUNIT_ASSERT(Rational(1, 2) <= ShortRational(1));
+       CPPUNIT_ASSERT(ShortRational(1, 2) <= Rational(1));
+       CPPUNIT_ASSERT(Rational(0) > ShortRational(-1));
+       CPPUNIT_ASSERT(ShortRational(0) > Rational(-1));
+       CPPUNIT_ASSERT(Rational(1) >= ShortRational(-1, 2));
+       CPPUNIT_ASSERT(ShortRational(1) >= Rational(-1, 2));
+}
+
+void RationalTest::testSum() {
+       CPPUNIT_ASSERT_EQUAL(
+                       Rational(3, 4),
+                       Rational(1, 4) + Rational(1, 2));
+}
+
+void RationalTest::testProduct() {
+       CPPUNIT_ASSERT_EQUAL(
+                       Rational(8),
+                       Rational(2) * 4);
+       CPPUNIT_ASSERT_EQUAL(
+                       Rational(4),
+                       Rational(2) / 0.5);
+       CPPUNIT_ASSERT_EQUAL(
+                       Rational(3),
+                       Rational(15) / Rational(5));
+       CPPUNIT_ASSERT_EQUAL(
+                       Rational(3),
+                       Rational(15) / 5);
+}
+
+}
diff --git a/tests/math/RationalTest.h b/tests/math/RationalTest.h
new file mode 100644 (file)
index 0000000..e288160
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef TEST_MATH_RATIONALTEST_H_
+#define TEST_MATH_RATIONALTEST_H_
+
+#include "../../src/math/Rational.h"
+
+#include <cmath>
+#include <limits>
+#include <cppunit/extensions/HelperMacros.h>
+
+
+namespace test_math {
+
+class RationalTest
+: public CppUnit::TestFixture {
+
+CPPUNIT_TEST_SUITE(RationalTest);
+CPPUNIT_TEST(testConversion);
+CPPUNIT_TEST(testComparison);
+CPPUNIT_TEST(testSum);
+CPPUNIT_TEST(testProduct);
+CPPUNIT_TEST_SUITE_END();
+
+public:
+       void setUp();
+       void tearDown();
+
+       void testConversion();
+       void testComparison();
+       void testSum();
+       void testProduct();
+       void testModulo();
+
+};
+
+}
+
+#endif