Skip to content

Commit

Permalink
Flesh out Fraction class
Browse files Browse the repository at this point in the history
This is to support fraction based manadatory sidestake allocations.
  • Loading branch information
jamescowens committed Jan 20, 2024
1 parent 878e4ff commit f3707bb
Showing 1 changed file with 274 additions and 9 deletions.
283 changes: 274 additions & 9 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "hash.h"

#include <memory>
#include <numeric>
#include <utility>
#include <map>
#include <vector>
Expand Down Expand Up @@ -160,13 +161,25 @@ inline int64_t abs64(int64_t n)
return (n >= 0 ? n : -n);
}

// Small class to represent fractions. We could do more sophisticated things like reduction using GCD, and overloaded
// multiplication, but we don't need it, because this is used in very limited places, and we actually in many of the
// algorithms where this needs to be used need to carefully control the order of multiplication and division using the
// numerator and denominator.
//!
//! \brief Class to represent fractions and common operations with built in simplification. This supports integer operations
//! for consensus critical code where floating point would cause problems across different architectures and/or compiler
//! implementations
//!
class Fraction {
public:
Fraction() {}
Fraction()
: m_numerator(0)
, m_denominator(1)
{}

Fraction(const Fraction& f)
: Fraction(f.GetNumerator(), f.GetDenominator())
{}

Fraction(const Fraction& f, const bool& simplify)
: Fraction(f.GetNumerator(), f.GetDenominator(), simplify)
{}

Fraction(const int64_t& numerator,
const int64_t& denominator)
Expand All @@ -178,9 +191,44 @@ class Fraction {
}
}

bool isNonZero()
Fraction(const int64_t& numerator,
const int64_t& denominator,
const bool& simplify)
: Fraction(numerator, denominator)
{
if (simplify) {
Simplify();
}
}

Fraction(const int64_t& numerator)
: Fraction(numerator, 1)
{}

bool isZero() const
{
// The denominator cannot be zero by construction rules.
return m_numerator == 0;
}

bool isNonZero() const
{
return !isZero();
}

bool isPositive() const
{
return (m_denominator > 0 && m_numerator > 0) || (m_denominator < 0 && m_numerator < 0);
}

bool isNonNegative() const
{
return m_denominator != 0 && m_numerator != 0;
return isPositive() || isZero();
}

bool isNegative() const
{
return !isNonNegative();
}

constexpr int64_t GetNumerator() const
Expand All @@ -193,9 +241,226 @@ class Fraction {
return m_denominator;
}

bool IsSimplified() const
{
return std::gcd(m_numerator, m_denominator) == (int64_t) 1;
}

void Simplify()
{
// Nice that we are at C++17! :)
int64_t gcd = std::gcd(m_numerator, m_denominator);

// If both numerator and denominator are negative,
// change the sign of gcd to flip both to positive.
if (m_numerator < 0 && m_denominator < 0) {
gcd = -gcd;
}

m_numerator = m_numerator / gcd;
m_denominator = m_denominator / gcd;

}

Fraction operator=(const Fraction& rhs)
{
m_numerator = rhs.GetNumerator();
m_denominator = rhs.GetDenominator();

return *this;
}

Fraction operator+(const Fraction& rhs) const
{
Fraction slhs(*this, true);
Fraction srhs(rhs, true);

return Fraction(slhs.GetNumerator() * srhs.GetDenominator() + slhs.GetDenominator() * srhs.GetNumerator(),
slhs.GetDenominator() * srhs.GetDenominator(), true);
}

Fraction operator+(const int64_t& rhs) const
{
Fraction slhs(*this, true);

return Fraction(slhs.GetNumerator() + rhs * slhs.GetDenominator(), slhs.GetDenominator(), true);
}

Fraction operator-(const Fraction& rhs) const
{
return (*this + Fraction(-rhs.GetNumerator(), rhs.GetDenominator()));
}

Fraction operator-(const int64_t& rhs) const
{
return (*this + -rhs);
}

Fraction operator*(const Fraction& rhs) const
{
Fraction slhs(*this, true);
Fraction srhs(rhs, true);

return Fraction(slhs.GetNumerator() * srhs.GetNumerator(), slhs.GetDenominator() * srhs.GetDenominator(), true);
}

Fraction operator*(const int64_t& rhs) const
{
Fraction slhs(*this, true);

return Fraction(slhs.GetNumerator() * rhs, slhs.GetDenominator(), true);
}

Fraction operator/(const Fraction& rhs) const
{
return (*this * Fraction(rhs.GetDenominator(), rhs.GetNumerator()));
}

Fraction operator/(const int64_t& rhs) const
{
Fraction slhs(*this, true);

return Fraction(slhs.GetNumerator(), slhs.GetDenominator() * rhs, true);
}

Fraction operator+=(const Fraction& rhs)
{
Simplify();

*this = *this + rhs;

return *this;
}

Fraction operator+=(const int64_t& rhs)
{
Simplify();

*this = *this + rhs;

return *this;
}

Fraction operator-=(const Fraction& rhs)
{
Simplify();

*this = *this - rhs;

return *this;
}

Fraction operator-=(const int64_t& rhs)
{
Simplify();

*this = *this - rhs;

return *this;
}

Fraction operator*=(const Fraction& rhs)
{
Simplify();

*this = *this * rhs;

return *this;
}

Fraction operator*=(const int64_t& rhs)
{
Simplify();

*this = *this * rhs;

return *this;
}

Fraction operator/=(const Fraction& rhs)
{
Simplify();

*this = *this / rhs;

return *this;
}

Fraction operator/=(const int64_t& rhs)
{
Simplify();

*this = *this / rhs;

return *this;
}

bool operator==(const Fraction& rhs) const
{
Fraction slhs(*this, true);
Fraction srhs(rhs, true);

return (slhs.GetNumerator() == srhs.GetNumerator() && slhs.GetDenominator() == slhs.GetDenominator());
}

bool operator!=(const Fraction& rhs) const
{
return !(*this == rhs);
}

bool operator<=(const Fraction& rhs) const
{
return (rhs - *this).isNonNegative();
}

bool operator>=(const Fraction& rhs) const
{
return (*this - rhs).isNonNegative();
}

bool operator<(const Fraction& rhs) const
{
return (rhs - *this).isPositive();
}

bool operator>(const Fraction& rhs) const
{
return (*this - rhs).isPositive();
}

bool operator==(const int64_t& rhs) const
{
return (*this == Fraction(rhs));
}

bool operator!=(const int64_t& rhs) const
{
return !(*this == rhs);
}

bool operator<=(const int64_t& rhs) const
{
return *this <= Fraction(rhs);
}

bool operator>=(const int64_t& rhs) const
{
return *this >= Fraction(rhs);
}

bool operator<(const int64_t& rhs) const
{
return *this < Fraction(rhs);
}

bool operator>(const int64_t& rhs) const
{
return *this > Fraction(rhs);
}

private:
int64_t m_numerator = 0;
int64_t m_denominator = 1;
int64_t m_numerator;
int64_t m_denominator;
};

inline std::string leftTrim(std::string src, char chr)
Expand Down

0 comments on commit f3707bb

Please sign in to comment.