I have a rational number class is made up of two integers: num
, the nominator, and den
, the denominator.
The following operator is supposed to read the rational number from a stream.
istream& operator >> (istream& Is, rational& r) {
char c; //Test char.
double n; //Could be either the numerator of the fraction or the antiperiod of the repeating decimal number.
Is >> n;
int i = 0;
for (; n*10-pow(10, i+1) < 1 && int(n) != 0; i++) {
n *= 10;
}
for (; int(n*10) % 10; i++) {
n *= 10;
}
n /= pow(10, i);
if (i == 0) {
r.num = n;
Is >> ws;
c = Is.peek();
if (c == '/') {
c = Is.get();
Is >> r.den;
} else {
r.den = 1;
}
r.normalize(); //This function normalizes the fraction.
} else {
Is >> ws;
c = Is.peek();
if (c == 'p' || c == 'P') {
int p; //Period of the repeating decimal number.
c = Is.get();
Is >> p;
vector<int> a = genFrac(n, p); //This function returns the fraction which express the decimal repeating number. It returns a "vector<int>" with the nominator at index 1 e denominator at index 0.
r.num = a[1];
r.den = a[0];
} else {
i = 0;
for (; n*10-pow(10, i+1) < 1 && int(n) != 0; i++) {
n *= 10;
}
for (; int(n*10) % 10 != 0; i++) {
n *= 10;
}
int pot10 = pow(10, i);
r.num = n;
r.den = pot10;
}
r.normalize();
}
return Is;
}
I wrote this code to implement the input of my "rational" class. I modified it from the one written in my C++ book in order to make possible the input of decimal numbers, including repeating ones.
It should be able to handle these types of input:
But it doesn't work, not even the part I copied from the book.
Can anyone help me?
I think I'd write this somewhat differently1.
Unless you really need to do otherwise, I'd start by reading an entire "chunk" of input (i.e., all the characters up to the next white space), then sort out how that's supposed to represent a number, and call a separate function for each possible representation:
std::istream &operator>>(std::istream &is, rational &r) {
std::string temp;
Is >> temp;
if (temp.find('/') != std::string::npos)
r = cvt_fraction(temp, Is);
else if (temp.find_first_of("pP") != std::string::npos)
r = cvt_repeating(temp, Is);
else if (temp.find('.') != std::string::npos)
r = cvt_float(temp, Is);
else
r = cvt_int(temp, Is);
return Is;
}
I've passed the istream to each for two reasons: first, so if they find garbage in the input, they can set the stream's fail bit. Second, so if they really do need to read more input, they can (but I'd be a little surprised if that's ever really needed).
It seems to me that each of those conversion functions should be fairly trivial: if I'm starting from the fact that a string should be digits "/" digits
or `digits "p" digits", doing a conversion is generally going to be pretty simple -- specifically, simple enough that I think just about anybody can probably glance at the code and sort out what each piece is supposed to do.
operator>>
, I would have one of two possible reactions: if it apparently had a bug, replace it immediately. Otherwise, put it on the "technical debt" list, and replace it as soon as possible. The simple fact is that as it stands right now, it takes a fair amount of study to even be sure what input formats are supposed to be supported, not to mention which part of the code handles each, or how the whole thing is supposed to work together to produce a meaningful result.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