Skip to content

Commit

Permalink
feat(numbers)!: wip - rationals ops
Browse files Browse the repository at this point in the history
  • Loading branch information
TheRustifyer committed Sep 5, 2024
1 parent e62aef3 commit dc8e14c
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 63 deletions.
44 changes: 43 additions & 1 deletion zero/ifc/math/numbers/numbers.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,53 @@ export import :numbers.integers;
export import :numbers.rationals;
export import :general;

import math.ops;

export namespace zero::math {


/// Private helper function to perform the common logic for addition and subtraction
/// @param rhs The rational number to be added or subtracted.
/// \param sign
/// @return The sum of the two rational numbers.
///
/// This method handles both like and unlike fractions. If the denominators of
/// the two fractions are equal, it directly adds the numerators. Otherwise, it
/// finds the least common multiple (LCM) of the denominators and scales the
/// numerators to have the LCM as the common denominator before adding.
// TODO: move to the future impl module
[[nodiscard]] Rational sum_or_subtract(const Rational& lhs, const Rational& rhs, int sign) {
if (lhs == rhs) { // Like fractions
return {static_cast<int>(lhs.numerator()) + sign * static_cast<int>(rhs.numerator()),
static_cast<int>(lhs.denominator())
};
} else { // Unlike fractions
const int lhs_numerator = static_cast<int>(lhs.numerator());
const int rhs_numerator = sign * static_cast<int>(rhs.numerator());
const int lhs_denominator = static_cast<int>(lhs.denominator());
const int rhs_denominator = static_cast<int>(rhs.denominator());

// Get their lcd by finding their lcm
const auto lcd = zero::math::lcm(lhs_denominator, rhs_denominator);

// Scale numerators to have the common denominator (lcm)
const int numerator = (lhs_numerator * (lcd / lhs_denominator)) + (rhs_numerator * (lcd / rhs_denominator));

return {numerator, lcd};
}
}


template <Numerical L, Numerical R>
constexpr auto operator+(const L& lhs, const R& rhs) noexcept {
return arithmetic_op(lhs, rhs, [](auto a, auto b) { return a + b; });
if constexpr (std::is_same_v<L, Rational> || std::is_same_v<R, Rational>) {
const Rational _lhs = static_cast<Rational>(lhs);
const Rational _rhs = static_cast<Rational>(rhs);
const auto op = [&](auto a, auto b) { return sum_or_subtract(a, b, 1) ; };
return arithmetic_op(lhs, rhs, op);
}
else
return arithmetic_op(lhs, rhs, [](auto a, auto b) { return a + b; });
}

template <Numerical L, Numerical R>
Expand Down
68 changes: 6 additions & 62 deletions zero/ifc/math/numbers/rationals.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ export namespace zero::math {

// TODO complete arithmetic overloads
// Comparison operator overloads
[[nodiscard]] bool operator==(Rational rhs) const noexcept;
// TODO should we check that 4/2 is the same as 2/1 right? Or we should maintain the difference and explicitly
// say that 4/2 aren't the same Rational number as 2/1?
[[nodiscard]] bool operator==(const Rational rhs) const noexcept {
// return _numerator == rhs.numerator() && _denominator == rhs.denominator();
return _numerator.number() == rhs.numerator().number() && _denominator.number() == rhs.denominator().number();
}

// Printable
friend std::ostream &operator<<(std::ostream& os, const Rational& rhs) {
Expand All @@ -74,68 +79,7 @@ export namespace zero::math {
};
}

using namespace zero::math;

/// Private helper function to perform the common logic for addition and subtraction
/// @param rhs The rational number to be added or subtracted.
/// \param sign
/// @return The sum of the two rational numbers.
///
/// This method handles both like and unlike fractions. If the denominators of
/// the two fractions are equal, it directly adds the numerators. Otherwise, it
/// finds the least common multiple (LCM) of the denominators and scales the
/// numerators to have the LCM as the common denominator before adding.
// TODO: move to the future impl module
[[nodiscard]] Rational sum_or_subtract(const Rational& lhs, const Rational& rhs, int sign) {
if (lhs == rhs) { // Like fractions
return {static_cast<int>(lhs.numerator()) + sign * static_cast<int>(rhs.numerator()),
static_cast<int>(lhs.denominator())
};
} else { // Unlike fractions
const int lhs_numerator = static_cast<int>(lhs.numerator());
const int rhs_numerator = sign * static_cast<int>(rhs.numerator());
const int lhs_denominator = static_cast<int>(lhs.denominator());
const int rhs_denominator = static_cast<int>(rhs.denominator());

// Get their lcd by finding their lcm
const auto lcd = zero::math::lcm(lhs_denominator, rhs_denominator);

// Scale numerators to have the common denominator (lcm)
const int numerator = (lhs_numerator * (lcd / lhs_denominator)) + (rhs_numerator * (lcd / rhs_denominator));

return {numerator, lcd};
}
}

/*+++++++++++++++++ Rationals +++++++++++++++++*/
// Arithmetic

// Addition operator
[[nodiscard]] Rational Rational::operator+(const Rational rhs) const {
return sum_or_subtract(*this, rhs, 1);
}
// Subtraction operator
[[nodiscard]] Rational Rational::operator-(const Rational rhs) const {
return sum_or_subtract(*this, rhs, -1);
}
/* [[nodiscard]] Rational Rational::operator*(const Integer rhs) const {
return Rational(_numerator * rhs, _denominator);
} */
[[nodiscard]] Rational Rational::operator*(const Rational rhs) const {
/* return Rational(
_numerator * rhs.numerator(), _denominator * rhs.denominator()
); */
return Rational(1, rhs.numerator()); // FIXME: provisional while refactoring
}


// Equality

// TODO should we check that 4/2 is the same as 2/1 right? Or we should maintain the difference and explicitly
// say that 4/2 aren't the same Rational number as 2/1?
[[nodiscard]] bool Rational::operator==(const Rational rhs) const noexcept {
// return _numerator == rhs.numerator() && _denominator == rhs.denominator();
return _numerator.number() == rhs.numerator().number() && _denominator.number() == rhs.denominator().number();
}


0 comments on commit dc8e14c

Please sign in to comment.