I am working on implementing a class for a rational number, which of course involves overriding common operators like '==' and '!='. I'm pretty sure there is a stupid mistake somewhere that I am missing, don't hesitate to ask for any file that I haven't provided. Thanks!
rational.hpp:
#ifndef RATIONAL_HPP
#define RATIONAL_HPP
#include "test.hpp"
#include <cstdlib>
#include <iosfwd>
#include <iostream>
#include <assert.h>
// Mathematical helper functions.
//
// NOTE: These are defined in rational.cpp.
int gcd(int, int);
int lcm(int, int);
// Represents a rational number. The rational numbers are the set of
// numbers that can be represented as the quotient of two integers.
struct Rational
{
// TODO: Define the following:
// 1. A default constructor
int n;
int d;
Rational()
:n(0), d(1) {}
// 2. A constructor that takes an integer value
Rational(int num)
:n(num), d(1){}
// 3. A constructor that takes a pair of values
Rational(int numer, int denom)
:n(numer), d(denom) {
assert( d != 0);
int gcdnum;
if ((numer % denom) != 0){
//do nothing
}else{
gcdnum = gcd(numer, denom);
numer /= gcdnum;
denom /= gcdnum;
Rational(numer, denom);
}
}
// Returns the numerator.
int num() const {
return n;
}
// Returns the denominator
int den() const {
return d;
}
};
bool operator==(Rational a, Rational b){
return (a.n == b.n && a.d == b.d);
}
bool operator!=(Rational a, Rational b){
return (a.n != b.n && a.d != b.d);
}
bool operator < (Rational a, Rational b){
int lcdNum = lcm(a.d, b.d);
int newAN, newBN; //allows for comparisons without altering actuial value
newAN = a.n * lcdNum;
newBN = b.n * lcdNum;
return newAN < newBN;
}
bool operator > (Rational a, Rational b){
int lcdNum = lcm(a.d, b.d);
int newAN, newBN; //allows for comparisons without altering actuial value
newAN = a.n * lcdNum;
newBN = b.n * lcdNum;
return newAN > newBN;
}
bool operator <= (Rational a, Rational b){
int lcdNum = lcm(a.d, b.d);
int newAN, newBN; //allows for comparisons without altering actuial value
newAN = a.n * lcdNum;
newBN = b.n * lcdNum;
return newAN <= newBN;
}
bool operator >= (Rational a, Rational b){
int lcdNum = lcm(a.d, b.d);
int newAN, newBN; //allows for comparisons without altering actuial value
newAN = a.n * lcdNum;
newBN = b.n * lcdNum;
return newAN >= newBN;
}
// 3. The standard arithmetic operators
// - r1 + r2
// - r1 - r2
// - r1 * r2
// - r1 / r2
// - r1 / r2
Rational operator + (Rational a, Rational b){
int lcdNum = lcm(a.d, b.d);
int newAN, newBN; //allows for comparisons without altering actuial value
newAN = a.n * lcdNum;
newBN = b.n * lcdNum;
Rational c((newAN + newBN), (a.d * lcdNum));
return c;
}
Rational operator - (Rational a, Rational b){
int lcdNum = lcm(a.d, b.d);
int newAN, newBN; //allows for comparisons without altering actuial value
newAN = a.n * lcdNum;
newBN = b.n * lcdNum;
Rational c((newAN + newBN), (a.d * lcdNum));
return c;
}
Rational operator * (Rational a, Rational b){
Rational c((a.n * b.n), (a.d * b.d));
return c;
}
Rational operator / (Rational a, Rational b){
Rational c((a.n * b.d), (a.d * b.n)); //multiplies by the reciprocal
return c;
}
std::ostream& operator<<(std::ostream&, Rational);
std::istream& operator>>(std::istream&, Rational&);
#endif
rational.cpp:
//
// rational.hpp: Definition of rational class and its interace.
#include "rational.hpp"
#include <iostream>
// -------------------------------------------------------------------------- //
// Helper functions
// Compute the GCD of two integer values using Euclid's algorithm.
int
gcd(int a, int b)
{
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
// Compute the LCM of two integer values.
int
lcm(int a, int b)
{
return (std::abs(a) / gcd(a, b)) * std::abs(b);
}
// -------------------------------------------------------------------------- //
// Rational implementation
// TODO: Make this print integers when the denominator is 1.
std::ostream&
operator<<(std::ostream& os, Rational r)
{
if(r.den() == 1){
return os << r.num();
}else{
return os << r.num() << '/' << r.den();
}
}
// TODO: Make this read integer values if no '/' is given as a separator.
// You may assume that there is no space between the numerator and the
// slash. Hint, find and read the reference documentation for istream::peek().
std::istream&
operator>>(std::istream& is, Rational& r)
{
int p, q;
char c;
is >> p;
c = is.peek();
if (c == '/'){
is >> c >> q;
if (!is)
return is;
// Require that the divider to be a '/'.
if (c != '/') {
is.setstate(std::ios::failbit);
return is;
}
// Make sure that we didn't read p/0.
if (q == 0) {
is.setstate(std::ios::failbit);
return is;
}
r = Rational(p, q);
return is;
}else{
is.setstate(std::ios::failbit);
}
}
rc.cpp:
// main.cpp: rational number test suite
#include "rational.hpp"
#include <iostream>
#include <iomanip>
#include <unistd.h>
int
main()
{
// Determine if input is coming from a terminal.
bool term = isatty(0);
// This will continue reading until it reaches the end-of-input.
// If you are using this interactivly, type crtl-d to send the
// end of input character to the terminal.
while (std::cin) {
Rational r1;
Rational r2;
std::string op;
if (term)
std::cout << "> ";
std::cin >> r1 >> op >> r2;
if (!std::cin)
break;
// FIXME: Add all of the other overlaoded operators by adding
// cases for each of them.
if (op == "==")
std::cout << std::boolalpha << (r1 == r2) << '\n';
else if (op == "!=")
std::cout << std::boolalpha << (r1 != r2) << '\n';
else if (op == "<")
std::cout << std::boolalpha << (r1 < r2) << '\n';
else if (op == ">")
std::cout << std::boolalpha << (r1 > r2) << '\n';
else if (op == "<=")
std::cout << std::boolalpha << (r1 <= r2) << '\n';
else if (op == ">=")
std::cout << std::boolalpha << (r1 >= r2) << '\n';
else if (op == "+")
std::cout << (r1 + r2) << '\n';
else if (op == "-")
std::cout << (r1 - r2) << '\n';
else if (op == "*")
std::cout << (r1 * r2) << '\n';
else if (op == "/")
std::cout << (r1 / r2) << '\n';
else
std::cerr << "invalid operator: " << op << '\n';
}
// If we got to the end of the file without fatal errors,
// return success.
if (std::cin.eof())
return 0;
// Otherwise, diagnose errors in input and exit with an error
// code.
if (std::cin.fail()) {
std::cerr << "input error\n";
return 1;
}
return 0;
}
Every translation unit that #include
s your rational.hpp
is going to get the definition of the comparison operator functions, which will certainly result in duplicate definitions at link time.
Try sticking an "inline" keyword in front of them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With