void rational<IntType>::normalize() { // Avoid repeated construction IntType zero(0); if (den == zero) throw bad_rational(); // Handle the case of zero separately, to avoid division by zero if (num == zero) { den = IntType(1); return; } IntType g = gcd<IntType>(num, den); num /= g; den /= g; // Ensure that the denominator is positive if (den < zero) { num = -num; den = -den; } }
rational<IntType>& rational<IntType>::operator/= (const rational<IntType>& r) { // Protect against self-modification IntType r_num = r.num; IntType r_den = r.den; // Avoid repeated construction IntType zero(0); // Trap division by zero if (r_num == zero) throw bad_rational(); if (num == zero) return *this; // Avoid overflow and preserve normalization IntType gcd1 = gcd<IntType>(num, r_num); IntType gcd2 = gcd<IntType>(r_den, den); num = (num/gcd1) * (r_den/gcd2); den = (den/gcd2) * (r_num/gcd1); if (den < zero) { num = -num; den = -den; } return *this; }
void rational<IntType>::normalize() { // Avoid repeated construction IntType zero(0); if (den == zero) throw_exception( bad_rational() ); // Handle the case of zero separately, to avoid division by zero if (num == zero) { den = IntType(1); return; } IntType g = math::gcd(num, den); num /= g; den /= g; // Ensure that the denominator is positive if (den < zero) { num = -num; den = -den; } BOOST_ASSERT( this->test_invariant() ); }
rational<IntType>& rational<IntType>::operator/= (const rational<IntType>& r) { // Avoid repeated construction IntType zero(0); // Trap division by zero if (r.num == zero) throw bad_rational(); if (num == zero) return *this; // Avoid overflow and preserve normalization IntType gcd1 = gcd<IntType>(num, r.num); IntType gcd2 = gcd<IntType>(r.den, den); num = (num/gcd1) * (r.den/gcd2); den = (den/gcd2) * (r.num/gcd1); return *this; }
constexpr rational(Integer n, Integer d): num(std::move(n)), den(d == 0 ? throw bad_rational() : std::move(d)) {}