6.S096 | January IAP 2014 | Undergraduate

# Effective Programming in C and C++

Assignments

## Sample Solution to Assignment 2, Problem 3

#### Here are the contents of rational.h:

``````
#ifndef _6S096_RATIONAL_H
#define _6S096_RATIONAL_H

#include <cstdint>
#include <iosfwd>
#include <stdexcept>

class Rational {
intmax_t _num, _den;
public:
enum sign_type { POSITIVE, NEGATIVE };

Rational() : _num{0}, _den{1} {}
Rational( intmax_t numer ) : _num{numer}, _den{1} {}
Rational( intmax_t numer, intmax_t denom ) : _num{numer}, _den{denom} { normalize(); }

inline intmax_t num() const { return _num; }
inline intmax_t den() const { return _den; }

void normalize();
float to_float()const;
double to_double()const;
sign_type sign() const;
Rational inverse() const;
};

std::ostream& operator<<( std::ostream& os, const Rational &ratio );

inline bool operator==( const Rational &lhs, const Rational &rhs ) {
return lhs.num() * rhs.den() == rhs.num() * lhs.den();
}

inline bool operator<( const Rational &lhs, const Rational &rhs ) {
if( lhs.sign() == Rational::POSITIVE && rhs.sign() == Rational::POSITIVE ) {
return lhs.num() * rhs.den() < rhs.num() * lhs.den();
} else if( lhs.sign() == Rational::NEGATIVE && rhs.sign() == Rational::NEGATIVE ) {
return lhs.num() * rhs.den() > rhs.num() * lhs.den();
} else {
return lhs.sign() == Rational::NEGATIVE;
}
}

inline Rational operator*( const Rational &a, const Rational &b ) {
return Rational{ a.num() * b.num(), a.den() * b.den() };
}

inline Rational operator+( const Rational &a, const Rational &b ) {
return Rational{ a.num() * b.den() + b.num() * a.den(), a.den() * b.den() };
}

inline Rational operator-( const Rational &a, const Rational &b ) {
return Rational{ a.num() * b.den() - b.num() * a.den(), a.den() * b.den() };
}

inline Rational operator/( const Rational &a, const Rational &b ) {
return a * b.inverse();
}

class bad_rational : public std::domain_error {
public:
};

#endif // _6S096_RATIONAL_H
``````

#### Here is the source code file rational.cpp:

``````
#include "rational.h"
#include "gcd.h"

#include <stdexcept>
#include <ostream>
#include <iostream>
#include <cmath>

Rational Rational::inverse() const {
return Rational{ _den, _num };
}

Rational::sign_type Rational::sign()const {
return _num >= 0 ? POSITIVE : NEGATIVE;
}

std::ostream& operator<<( std::ostream& os, const Rational &ratio ) {
if( ratio == 0 ) {
os << "0";
} else {
if( ratio.sign() == Rational::NEGATIVE ) {
os << "-";
}
os << std::abs( ratio.num() ) << "/" << std::abs( ratio.den() );
}
return os;
}

void Rational::normalize() {
if( _den == 0 ) {
}

if( _num == 0 ) {
_den = 1; return;
}

auto g = gcd( std::abs( _num ), std::abs( _den ) );
_num /= g; _den /= g;

if( _den < 0 ) {
_num = -_num;
_den = -_den;
}
}

float Rational::to_float() const {
return static_cast<float>( _num ) / static_cast<float>( _den );
}

double Rational::to_double()const {
return static_cast<double>( _num ) / static_cast<double>( _den );
}
``````

#### Below is the output using the test data:

``````
rational:
1: OK [0.007 seconds] OK! add
2: OK [0.006 seconds] OK! mult
3: OK [0.009 seconds] OK! add1024
4: OK [0.014 seconds] OK! add1024
5: OK [0.158 seconds] OK! add32768
6: OK [0.007 seconds] OK! op<<
7: OK [0.289 seconds] OK! div65536 in 0.280000 s
8: OK [0.006 seconds] OK! phi, 0.000000e+00
9: OK [0.006 seconds] OK! (Bad rational: zero denominator)
10: OK [0.006 seconds] OK! xyz
11: OK [0.007 seconds] OK! pow2
12: OK [0.006 seconds] OK! x1z
``````