/** * file: triangle.cc * author: keller * purpose: pedagogical testing example: repeats the following until * end-of-file: * inputs three numbers, then determines * whether they form a triangle, and if so, what kind. * * The absolute values of the numbers must be in the range * .between +/- 1e-150 and 1e150, * otherwise the entire test case input will be rejected. * Negative numbers will be interpreted as their absolute value. **/ #include #include #include double MAX = 1e+150; // top of acceptable numeric range double MIN = 1e-150; // bottom of acceptable numberic range /** * Check whether the string astr represents a valid number * and, if so, whether the number is in the specified range. * If not valid or in range, "is out of range" is printed and false is * returned. Otherwise true is returned and a's value is set to the number. **/ bool inRange(const string astr, double& a, ostream& out) { // Get char* representation of string so that strtod can be used. const char* ptr = astr.c_str(); char* endptr; // After strtod, endptr will point to end of converted string. a = strtod(ptr, &endptr); delete ptr; // Prevent space leak. if( *endptr == 0 ) // if successful conversion ... { a = fabs(a); if( MIN <= a && a <= MAX ) // Check the actual range. { return true; } } out << "number " << astr << " is out of range" << endl; return false; } /** * Order numbers a and b so that a <= b. **/ void order(double& a, double& b) { if( a > b ) { double temp = a; a = b; b = temp; } // assert( a <= b ); } /** * Assumes a <= b && b <= c. * Return 1 if the triangle is a right triangle, otherwise return 0. **/ inline int isRight(double a, double b, double c) { return (a*a) + (b*b) == (c*c); } /** * Return 1 if the sides are equal, otherwise return 0. **/ inline int equal(double a, double b) { return a == b ? 1 : 0; } /** * Assumes a <= b && b <= c. * Analyze the triangle according to the following categories: * -1: not a triangle * 0: scalene triangle * 1: right scalene triangle * 2: isosceles triangle * 3: equilateral triangle * 4: right isosceles triangle **/ int analyze(double a, double b, double c) { if( a > (c - b) ) { switch( equal(a, b) + equal(b, c) ) { case 0: return isRight(a, b, c); case 1: return 2 + 2*isRight(a, b, c); case 2: return 3; } } return -1; // not a triangle } /** * Until end-of-file, read groups of three numbers and classify whether they * are all in range and could be the sides of a triangle, and if so, * what kind: * [right] {equilateral, isosceles, scalene} **/ void test(istream& in, ostream& out) { string astr, bstr, cstr; // read numbers as strings, exit loop if end-of-file while( in >> astr >> bstr >> cstr ) { out << astr << " " << bstr << " " << cstr << " "; // echo // Try to convert input strings to double; check range in the process. // If conversion fails, false is returned. Otherwise, numeric variables // are bound to the absolute values of the converted values. double a, b, c; if( inRange(astr, a, out) && inRange(bstr, b, out) && inRange(cstr, c, out) ) { // assert( a >= 0 && b >= 0 && c >= 0 ); order(a, b); order(b, c); order(a, b); // assert( a <= b && b <= c ) switch( analyze(a, b, c) ) { case -1: out << "not a triangle."; break; case 0: out << "scalene triangle."; break; case 1: out << "right scalene triangle."; break; case 2: out << "isosceles triangle."; break; case 3: out << "equilateral triangle."; break; case 4: out << "right isosceles triangle."; break; } out << endl; } } out << endl; } /** * Test the triangle tester. **/ int main() { test(cin, cout); return 0; } /* Change log: * * $Log: triangle.cc,v $ * Revision 1.26 2000/10/31 06:34:31 keller * Corrected error in MIN due to demoing to class. * * Revision 1.25 2000/10/31 00:56:34 keller * Reconciled missing max/min. * <<<<<<< triangle.cc ======= * Revision 1.24 2000/10/31 00:54:49 keller * Removed min. * * Revision 1.22 2000/10/31 00:48:07 keller * Swapped max and min for illustrations purposes. * >>>>>>> 1.24 * Revision 1.21 2000/10/31 00:45:25 keller * Took out header files for illustration purposes. * * Revision 1.20 2000/10/25 20:02:13 keller * Further cleanup in documentation and addition of test cases. * * Revision 1.19 2000/10/25 19:24:51 keller * Cleaned up code and commenting. * * Revision 1.18 2000/10/25 18:33:24 keller * Separated test from main. * * Revision 1.17 2000/10/25 18:25:40 keller * Modified main for greater clarity. * * Revision 1.15 2000/10/25 17:49:42 keller * Modified for greater clarity. * * Revision 1.14 2000/03/30 17:42:06 keller * changed the test for sides equal to not rely on the result of a==b being 1. * * Revision 1.11 2000/03/29 18:52:59 keller * reworked side-testing logic * * Revision 1.8 2000/03/29 07:04:39 keller * make sure that each number gets range checked even if earlier numbers * are out of range * */