morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
morph::math::Rational Struct Reference

Exact rational number with a runtime decimal-precision tag. More...

#include <rational.hpp>

Classes

struct  Wire
 Flat JSON representation used by the Glaze codec below. More...

Public Member Functions

constexpr Rational () noexcept=default
 Default-constructs the canonical zero (0/1) at precision 1.
constexpr Rational (std::int64_t whole, DecimalPlaces wantedPrecision) noexcept
 Constructs from a whole integer at the given precision.
constexpr Rational (Numerator wantedNumerator, Denominator wantedDenominator, DecimalPlaces wantedPrecision) noexcept
 Constructs from explicit numerator/denominator, then canonicalises.
constexpr DecimalPlaces getDecimalPlaces () const noexcept
 The value's current decimal precision.
constexpr bool isZero () const noexcept
 Whether the value equals 0/1.
constexpr bool isInteger () const noexcept
 Whether the value is an integer.
constexpr bool isNegative () const noexcept
 Whether the value is strictly less than zero.
double toDouble () const noexcept
 Converts to double, rounded to this value's decimalPlaces.
double toDouble (std::uint32_t requestedDecimalPlaces) const noexcept
 Converts to double, rounded to requestedDecimalPlaces.
constexpr Rational operator- () const noexcept
 Negates.
constexpr std::expected< Rational, RationalError > reciprocal () const noexcept
 Multiplicative inverse.
constexpr std::strong_ordering operator<=> (const Rational &other) const noexcept
 Three-way comparison. Value-only: ignores decimalPlaces.
constexpr bool operator== (const Rational &other) const noexcept
 Equality. Value-only: ignores decimalPlaces.
constexpr Rational & operator+= (const Rational &rhs) noexcept
 In-place addition. Result precision becomes max of the two. Uses reduce-before-multiply to extend the safe int64 range (Knuth 4.5.1).
constexpr Rational & operator-= (const Rational &rhs) noexcept
 In-place subtraction. Result precision becomes max of the two.
constexpr Rational & operator*= (const Rational &rhs) noexcept
 In-place multiplication. Result precision becomes max of the two. Cross-cancels common factors before multiplying.
constexpr std::expected< Rational, RationalError > dividedBy (const Rational &rhs) const noexcept
 Non-throwing division. Result precision becomes max of the two.
void setWire (Wire wire) noexcept
 Wire-codec entry (Glaze read side): rebuilds through the canonicalising constructor, clamping what it cannot represent.
Wire getWire () const noexcept
 Wire-codec exit (Glaze write side).
constexpr void addAssignChecked (const Rational &rhs) noexcept
 Applies +='s arithmetic, having already proven it cannot overflow.
constexpr void subAssignChecked (const Rational &rhs) noexcept
 Applies -='s arithmetic, having already proven it cannot overflow.
constexpr void mulAssignChecked (const Rational &rhs) noexcept
 Applies *='s arithmetic, having already proven it cannot overflow.
constexpr bool addWouldOverflow (const Rational &rhs) const noexcept
 Whether *this + rhs would overflow any intermediate or the result.
constexpr bool subWouldOverflow (const Rational &rhs) const noexcept
 Whether *this - rhs would overflow any intermediate or the result.
constexpr bool mulWouldOverflow (const Rational &rhs) const noexcept
 Whether *this * rhs would overflow, after cross-cancelling.

Static Public Member Functions

static constexpr std::expected< Rational, RationalError > from (Numerator wantedNumerator, Denominator wantedDenominator, DecimalPlaces wantedPrecision) noexcept
 Validating factory.
static std::expected< Rational, RationalError > fromFloat (double value, DecimalPlaces wantedPrecision) noexcept
 Converts a double to a Rational scaled to wantedPrecision.
static std::expected< Rational, RationalError > fromFloat (float value, DecimalPlaces wantedPrecision) noexcept
 Converts a float to a Rational scaled to wantedPrecision.
static std::expected< Rational, RationalError > fromFloat (long double value, DecimalPlaces wantedPrecision) noexcept
 Converts a long double to a Rational scaled to wantedPrecision.
static constexpr Rational zero (DecimalPlaces wantedPrecision) noexcept
 Canonical zero (0/1) at the given precision.
static constexpr Rational one (DecimalPlaces wantedPrecision) noexcept
 Canonical one (1/1) at the given precision.

Public Attributes

std::int64_t numerator {0}
 Signed numerator. Carries the sign of the rational value.
std::int64_t denominator {1}
 Strictly positive denominator. Never zero, never negative.
DecimalPlaces decimalPlaces {1}
 Decimal-precision tag. Invariant: 0 <= value <= kMaxDecimalPlaces.

Detailed Description

Exact rational number with a runtime decimal-precision tag.

Definition at line 375 of file rational.hpp.

Constructor & Destructor Documentation

◆ Rational() [1/2]

morph::math::Rational::Rational ( std::int64_t whole,
DecimalPlaces wantedPrecision )
inlineconstexprnoexcept

Constructs from a whole integer at the given precision.

Parameters
wholeThe integer value; stored as whole/1.
wantedPrecisionDecimal precision; clamped to [0, kMaxDecimalPlaces].

Definition at line 391 of file rational.hpp.

◆ Rational() [2/2]

morph::math::Rational::Rational ( Numerator wantedNumerator,
Denominator wantedDenominator,
DecimalPlaces wantedPrecision )
inlineconstexprnoexcept

Constructs from explicit numerator/denominator, then canonicalises.

A negative wantedDenominator flips the sign of wantedNumerator, the pair is reduced by gcd, and a denominator of 0 is clamped to 1. Use from for explicit zero-denominator detection.

Parameters
wantedNumeratorSigned numerator.
wantedDenominatorDenominator. May be negative or zero on input.
wantedPrecisionDecimal precision; clamped to [0, kMaxDecimalPlaces].

Definition at line 403 of file rational.hpp.

Member Function Documentation

◆ from()

constexpr std::expected< Rational, RationalError > morph::math::Rational::from ( Numerator wantedNumerator,
Denominator wantedDenominator,
DecimalPlaces wantedPrecision )
inlinestaticnodiscardconstexprnoexcept

Validating factory.

Parameters
wantedNumeratorSigned numerator.
wantedDenominatorDenominator; 0 is rejected instead of clamped.
wantedPrecisionDecimal precision; clamped to [0, kMaxDecimalPlaces].
Returns
The canonical rational, or DivisionByZero if wantedDenominator is 0.

Definition at line 416 of file rational.hpp.

◆ fromFloat() [1/3]

std::expected< Rational, RationalError > morph::math::Rational::fromFloat ( double value,
DecimalPlaces wantedPrecision )
inlinestaticnodiscardnoexcept

Converts a double to a Rational scaled to wantedPrecision.

Parameters
valueSource value.
wantedPrecisionDecimal precision to scale to.
Returns
A canonical Rational, or an error (NotFinite / Overflow).
Note
noexcept but not constexpr — uses std::llround / std::isfinite.

Definition at line 1420 of file rational.hpp.

◆ fromFloat() [2/3]

std::expected< Rational, RationalError > morph::math::Rational::fromFloat ( float value,
DecimalPlaces wantedPrecision )
inlinestaticnodiscardnoexcept

Converts a float to a Rational scaled to wantedPrecision.

Parameters
valueSource value.
wantedPrecisionDecimal precision to scale to.
Returns
A canonical Rational, or an error (NotFinite / Overflow).

Definition at line 1425 of file rational.hpp.

◆ fromFloat() [3/3]

std::expected< Rational, RationalError > morph::math::Rational::fromFloat ( long double value,
DecimalPlaces wantedPrecision )
inlinestaticnodiscardnoexcept

Converts a long double to a Rational scaled to wantedPrecision.

Parameters
valueSource value.
wantedPrecisionDecimal precision to scale to.
Returns
A canonical Rational, or an error (NotFinite / Overflow).

Definition at line 1430 of file rational.hpp.

◆ zero()

constexpr Rational morph::math::Rational::zero ( DecimalPlaces wantedPrecision)
inlinestaticnodiscardconstexprnoexcept

Canonical zero (0/1) at the given precision.

Parameters
wantedPrecisionDecimal precision of the returned value.
Returns
0/1 tagged with wantedPrecision.

Definition at line 449 of file rational.hpp.

◆ one()

constexpr Rational morph::math::Rational::one ( DecimalPlaces wantedPrecision)
inlinestaticnodiscardconstexprnoexcept

Canonical one (1/1) at the given precision.

Parameters
wantedPrecisionDecimal precision of the returned value.
Returns
1/1 tagged with wantedPrecision.

Definition at line 456 of file rational.hpp.

◆ getDecimalPlaces()

DecimalPlaces morph::math::Rational::getDecimalPlaces ( ) const
inlinenodiscardconstexprnoexcept

The value's current decimal precision.

Returns
The decimalPlaces tag.

Definition at line 462 of file rational.hpp.

◆ isZero()

bool morph::math::Rational::isZero ( ) const
inlinenodiscardconstexprnoexcept

Whether the value equals 0/1.

Returns
true if the numerator is zero.

Definition at line 466 of file rational.hpp.

◆ isInteger()

bool morph::math::Rational::isInteger ( ) const
inlinenodiscardconstexprnoexcept

Whether the value is an integer.

Returns
true if the denominator is 1.

Definition at line 470 of file rational.hpp.

◆ isNegative()

bool morph::math::Rational::isNegative ( ) const
inlinenodiscardconstexprnoexcept

Whether the value is strictly less than zero.

Returns
true if the numerator is negative.

Definition at line 474 of file rational.hpp.

◆ toDouble() [1/2]

double morph::math::Rational::toDouble ( ) const
inlinenodiscardnoexcept

Converts to double, rounded to this value's decimalPlaces.

Returns
The rounded floating-point reading.

Definition at line 478 of file rational.hpp.

◆ toDouble() [2/2]

double morph::math::Rational::toDouble ( std::uint32_t requestedDecimalPlaces) const
inlinenodiscardnoexcept

Converts to double, rounded to requestedDecimalPlaces.

Parameters
requestedDecimalPlacesNumber of decimal digits to keep. Values > 18 fall back to unrounded conversion.
Returns
The rounded floating-point reading.

Definition at line 1435 of file rational.hpp.

◆ operator-()

Rational morph::math::Rational::operator- ( ) const
inlinenodiscardconstexprnoexcept

Negates.

Note
Negating a Rational built from INT64_MIN overflows.
Returns
The value with the numerator's sign flipped.

Definition at line 488 of file rational.hpp.

◆ reciprocal()

std::expected< Rational, RationalError > morph::math::Rational::reciprocal ( ) const
inlinenodiscardconstexprnoexcept

Multiplicative inverse.

Returns
denominator/numerator, or unexpected(DivisionByZero) if zero.

Definition at line 494 of file rational.hpp.

◆ operator<=>()

std::strong_ordering morph::math::Rational::operator<=> ( const Rational & other) const
inlinenodiscardconstexprnoexcept

Three-way comparison. Value-only: ignores decimalPlaces.

Exact for the full int64 range: cross-products are computed in 128 bits, so the ordering is always consistent with operator==.

Parameters
otherValue to compare against.
Returns
The ordering of the two exact values.

Definition at line 510 of file rational.hpp.

◆ operator==()

bool morph::math::Rational::operator== ( const Rational & other) const
inlinenodiscardconstexprnoexcept

Equality. Value-only: ignores decimalPlaces.

Parameters
otherValue to compare against.
Returns
true when the canonical pairs are identical.

Definition at line 540 of file rational.hpp.

◆ operator+=()

Rational & morph::math::Rational::operator+= ( const Rational & rhs)
inlineconstexprnoexcept

In-place addition. Result precision becomes max of the two. Uses reduce-before-multiply to extend the safe int64 range (Knuth 4.5.1).

Saturates rather than overflowing. If the exact sum – or any intermediate cross-term needed to reach it – is not representable, this logs at error and clamps to the largest magnitude of the correct sign instead of committing signed-overflow undefined behaviour. See saturateToward for why a defined wrong answer beats UB here.

Parameters
rhsValue to add.
Returns
*this.

Definition at line 554 of file rational.hpp.

◆ operator-=()

Rational & morph::math::Rational::operator-= ( const Rational & rhs)
inlineconstexprnoexcept

In-place subtraction. Result precision becomes max of the two.

Saturates rather than overflowing; see operator+=.

Parameters
rhsValue to subtract.
Returns
*this.

Definition at line 569 of file rational.hpp.

◆ operator*=()

Rational & morph::math::Rational::operator*= ( const Rational & rhs)
inlineconstexprnoexcept

In-place multiplication. Result precision becomes max of the two. Cross-cancels common factors before multiplying.

Parameters
rhsValue to multiply by.
Returns
*this.

Saturates rather than overflowing; see operator+=.

Definition at line 585 of file rational.hpp.

◆ dividedBy()

std::expected< Rational, RationalError > morph::math::Rational::dividedBy ( const Rational & rhs) const
inlinenodiscardconstexprnoexcept

Non-throwing division. Result precision becomes max of the two.

Reports a zero divisor; saturates on overflow. The expected says only whether rhs was zero. Division is multiplication by the divisor's reciprocal, and that product saturates exactly like operator*=: a quotient too large for int64_t clamps to ±INT64_MAX/1, logs at error, and is still returned as a successful expected. INT64_MAX / (1/1000000) is such a case. A caller that must not absorb a clamped quotient uses checkedDiv, which routes both failure modes through the one channel.

Parameters
rhsDivisor.
Returns
*this / rhs — possibly saturated — or unexpected(DivisionByZero) if rhs is zero.

Definition at line 603 of file rational.hpp.

◆ setWire()

void morph::math::Rational::setWire ( Wire wire)
inlinenoexcept

Wire-codec entry (Glaze read side): rebuilds through the canonicalising constructor, clamping what it cannot represent.

den == 0, an out-of-range dp, or a component whose magnitude does not fit are clamped rather than rejected, so this never fails — which means {"num":5,"den":0,"dp":2} decodes to a perfectly plausible 5/1, and nothing downstream can tell the value was altered.

Rejecting here would be the wrong layer's call. Whether a clamped value is a protocol violation or a harmless normalisation depends on where the bytes came from, and this function cannot know. It records the fact instead, for a WireClampScope around the decode to act on.

Parameters
wireRaw values decoded from JSON.

Definition at line 661 of file rational.hpp.

◆ getWire()

Wire morph::math::Rational::getWire ( ) const
inlinenodiscardnoexcept

Wire-codec exit (Glaze write side).

Returns
The canonical members, ready for JSON encoding.

Definition at line 674 of file rational.hpp.

◆ addAssignChecked()

void morph::math::Rational::addAssignChecked ( const Rational & rhs)
inlineconstexprnoexcept

Applies +='s arithmetic, having already proven it cannot overflow.

For checkedAdd, which has just run addWouldOverflow and must not re-enter operator+='s saturating path. Calling this without that check is undefined on overflow – the check is the precondition.

Parameters
rhsValue to add.

Definition at line 852 of file rational.hpp.

◆ subAssignChecked()

void morph::math::Rational::subAssignChecked ( const Rational & rhs)
inlineconstexprnoexcept

Applies -='s arithmetic, having already proven it cannot overflow.

Parameters
rhsValue to subtract.

Definition at line 856 of file rational.hpp.

◆ mulAssignChecked()

void morph::math::Rational::mulAssignChecked ( const Rational & rhs)
inlineconstexprnoexcept

Applies *='s arithmetic, having already proven it cannot overflow.

Parameters
rhsValue to multiply by.

Definition at line 860 of file rational.hpp.

◆ addWouldOverflow()

bool morph::math::Rational::addWouldOverflow ( const Rational & rhs) const
inlinenodiscardconstexprnoexcept

Whether *this + rhs would overflow any intermediate or the result.

Parameters
rhsThe addend.
Returns
true if the addition cannot be performed exactly.

Definition at line 865 of file rational.hpp.

◆ subWouldOverflow()

bool morph::math::Rational::subWouldOverflow ( const Rational & rhs) const
inlinenodiscardconstexprnoexcept

Whether *this - rhs would overflow any intermediate or the result.

Parameters
rhsThe subtrahend.
Returns
true if the subtraction cannot be performed exactly.

Definition at line 878 of file rational.hpp.

◆ mulWouldOverflow()

bool morph::math::Rational::mulWouldOverflow ( const Rational & rhs) const
inlinenodiscardconstexprnoexcept

Whether *this * rhs would overflow, after cross-cancelling.

Checks the cross-cancelled factors operator*= actually multiplies: cross-cancelling is what keeps most products in range, so checking the raw operands would reject pairs that multiply perfectly well.

Parameters
rhsThe factor.
Returns
true if the product cannot be represented.

Definition at line 895 of file rational.hpp.

Member Data Documentation

◆ numerator

std::int64_t morph::math::Rational::numerator {0}

Signed numerator. Carries the sign of the rational value.

Definition at line 377 of file rational.hpp.

◆ denominator

std::int64_t morph::math::Rational::denominator {1}

Strictly positive denominator. Never zero, never negative.

Definition at line 380 of file rational.hpp.

◆ decimalPlaces

DecimalPlaces morph::math::Rational::decimalPlaces {1}

Decimal-precision tag. Invariant: 0 <= value <= kMaxDecimalPlaces.

Definition at line 383 of file rational.hpp.


The documentation for this struct was generated from the following file: