Download
slide1 n.
Skip this Video
Loading SlideShow in 5 Seconds..
CHAPTER 8 Multidimensional Arrays PowerPoint Presentation
Download Presentation
CHAPTER 8 Multidimensional Arrays

CHAPTER 8 Multidimensional Arrays

148 Views Download Presentation
Download Presentation

CHAPTER 8 Multidimensional Arrays

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. CHAPTER 8 Multidimensional Arrays • Arrays of Arrays • Matrix Operations CHAPTER 8 – Multidimensional Arrays 116

  2. ARRAYS OF ARRAYS //////////////////////////////////////////////////// // OneWeekGrid.h // // This class implements a 7x24 grid of integers, // // which keeps track of counts foreach hour in a // // one-week period. It also implements an output // // operator to output a formatted version of the // // two-dimensional grid. // //////////////////////////////////////////////////// #ifndefONE_WEEK_GRID_H #include <iostream> #include <iomanip> #include <fstream> #include <string> using namespace std; const string DAY_OF_WEEK[] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY" }; // CLASS DEFINITION // classOneWeekGrid { public: OneWeekGrid(); OneWeekGrid(constOneWeekGrid &grid); voidaddItem(string day, string militaryTime); intmaxItem() const; friendostream& operator << (ostream &outputFile, constOneWeekGrid &grid); private: intitemCount[7][24]; }; When a grid of values is needed in a program, the notion of a linear, one-dimensional array can be extended into additional dimensions by essentially making an array of arrays. Note that the itemCount data member has been defined as a 7-row, 24-column array of integers. CHAPTER 8 – Multidimensional Arrays 117

  3. // CLASS IMPLEMENTATION // // Default Constructor: Initializes the grid elements to zero. OneWeekGrid::OneWeekGrid() { int weekday; int hour; for (weekday = 0; weekday < 7; weekday++) for (hour = 0; hour < 24; hour++) itemCount[weekday][hour] = 0; } // Copy Constructor: Duplicates the parameterized OneWeekGrid. OneWeekGrid::OneWeekGrid(constOneWeekGrid &grid) { int weekday; int hour; for (weekday = 0; weekday < 7; weekday++) for (hour = 0; hour < 24; hour++) itemCount[weekday][hour] = grid.itemCount[weekday][hour]; Note that the itemCount data member is loaded with values in each constructor by using a nested for-loop, with the inner loop traversing the columns and the outer loop traversing the rows. CHAPTER 8 – Multidimensional Arrays 118

  4. // Member Function addItem: Increments the count for the grid element corresponding to the // day parameter (a string representing a day - "Sunday", "Monday", etc. - which is converted // into the appropriate row number - 0, 1, etc.) and the militaryTime parameter (which is // converted from a string, such as "1530", into the corresponding column number, such as 15). voidOneWeekGrid::addItem(string day, string militaryTime) { intdayNumber; int hour = 10 * ( int(militaryTime[0]) - int('0') ) + ( int(militaryTime[1]) - int('0') ); switch (day[0]) { case'S': { dayNumber = (day.length() == 6) ? 0 : 6; break; } case'M': { dayNumber = 1; break; } case'T': { dayNumber = (day.length() == 7) ? 2 : 4; break; } case'W': { dayNumber = 3; break; } case'F': { dayNumber = 5; break; } default : return; } itemCount[dayNumber][hour]++; return; } // Member function maxItem: Returns the largest value in the grid. intOneWeekGrid::maxItem() const { intmaxValue = 0; int weekday; int hour; for (weekday = 0; weekday < 7; weekday++) for (hour = 0; hour < 24; hour++) if (itemCount[weekday][hour] > maxValue) maxValue = itemCount[weekday][hour]; returnmaxValue; } Another nested for-loop to traverse the entire two-dimensional array. CHAPTER 8 – Multidimensional Arrays 119

  5. // Output Operator: Outputs the grid, with standardized widths for each value (to // facilitate lining the columns up), spaces between consecutive row elements, and // line feeds separating consecutive rows. ostream& operator << (ostream &outputFile, constOneWeekGrid &grid) { int weekday, hour, digitIndex; intmaxVal = grid.maxItem(); intnbrDigits = 0; while (maxVal > 0) { nbrDigits++; maxVal /= 10; } if (nbrDigits < 2) nbrDigits = 2; outputFile << setw(11) << " "; for (hour = 0; hour < 24; hour++) outputFile << setw(nbrDigits) << hour << " "; outputFile << endl << setw(11) << " "; for (hour = 0; hour < 24; hour++) { for (digitIndex = 1; digitIndex <= nbrDigits; digitIndex++) outputFile << '-'; outputFile << " "; } outputFile << endl; In this nested for-loop, the inner loop lines up the values in each row so they form output columns, while the outer loop ensures that each row starts with a day-of-the-week label and ends with a linefeed. for (weekday = 0; weekday < 7; weekday++) { outputFile << setw(9) << DAY_OF_WEEK[weekday] << ": "; for (hour = 0; hour < 24; hour++) outputFile << setw(nbrDigits) << grid.itemCount[weekday][hour] << " "; outputFile << endl; } returnoutputFile; } #define ONE_WEEK_GRID_H #endif CHAPTER 8 – Multidimensional Arrays 120

  6. ////////////////////////////////////////////////////// // This program uses the oneWeekGrid class to input // // a full week's data from a user-specified file, // // counting every occurrence of every hour in every // // day that occurs in the file. It then outputs the // // result to a user-specified output file. // ////////////////////////////////////////////////////// #include <iostream> #include <fstream> #include <string> #include "OneWeekGrid.h" using namespace std; voidloadGrid(OneWeekGrid &grid, ifstream &file); // The main function queries the user for the file names, opens // the files, loads and outputs the grid, and closes the files. void main() { OneWeekGridweekGrid; string inputFileName, outputFileName; ifstreaminputFile; ofstreamoutputFile; cout << "Specify the name of the input file containing the day/time data: "; cin >> inputFileName; inputFile.open(inputFileName.c_str()); cout << endl << endl; loadGrid(weekGrid, inputFile); inputFile.close(); The driver program starts by loading the two-dimensional array with contents of a user-defined input file, using its own loadGrid function. CHAPTER 8 – Multidimensional Arrays 121

  7. cout << "Specify the name of the output file to contain the week's hourly data: "; cin >> outputFileName; outputFile.open(outputFileName.c_str()); cout << endl << endl; outputFile << weekGrid; outputFile.close(); return; } // The loadGrid function repeatedly retrieves day/time string // pairs from the input file and updates the grid acccordingly. voidloadGrid(OneWeekGrid &grid, ifstream &file) { string dayOfWeek; string timeOfDay; file >> dayOfWeek; while (!file.eof()) { file >> timeOfDay; grid.addItem(dayOfWeek, timeOfDay); file >> dayOfWeek; } return; } The driver program finishes by outputting the two-dimensional array via the overloaded output operator in the OneWeekGrid class. The loadGrid function uses the addItem member function of the OneWeekGrid class in order to update each value in the two-dimensional array that comprises the data member of that class. CHAPTER 8 – Multidimensional Arrays 122

  8. Tuesday 2100 Thursday 1116 Saturday 0159 Friday 1339 Sunday 1602 Thursday 0156 Sunday 0446 Sunday 1816 Saturday 0829 Monday 1414 Wednesday 0414 Monday 0310 Wednesday 2001 Friday 1201 Monday 1008 Saturday 1830 Wednesday 1911 Tuesday 1921 Monday 2055 Monday 2354 Wednesday 1640 Monday 2359 Monday 0603 Thursday 0801 Friday 1557 Saturday 1336 Friday 0718 Friday 0803 Tuesday 0111 Monday 1138 Sunday 0118 Sunday 1317 Friday 1916 Saturday 1032 Saturday 0632 Sunday 1458 Monday 1957 Tuesday 2131 Monday 0237 Saturday 1308 Saturday 1536 Tuesday 1516 Sunday 1715 Wednesday 0150 Monday 0823 Sunday 1717 Thursday 0549 Monday 0340 Thursday 0759 Tuesday 1532 Saturday 1021 Sunday 1039 Wednesday 0705 Tuesday 1016 Thursday 0806 Wednesday 0823 Sunday 1427 Thursday 2256 Sunday 1734 Tuesday 1316 Thursday 0645 Thursday 0737 Thursday 0321 Saturday 0503 Sunday 1118 Tuesday 1300 Thursday 2010 Sunday 2301 Tuesday 0431 Thursday 0210 Saturday 1928 Friday 0628 Thursday 1606 Saturday 1711 Tuesday 2119 Monday 1342 Thursday 0601 Sunday 1053 Tuesday 0945 Saturday 0305 Wednesday 0704 Sunday 1110 Saturday 0541 Monday 0520 Wednesday 0636 Sunday 1406 Tuesday 1612 Wednesday 0700 Friday 1501 Saturday 0633 Monday 0330 Wednesday 0943 Wednesday 1129 Sunday 0436 Tuesday 1731 Saturday 1500 Friday 1325 Friday 1631 Friday 1311 Thursday 1850 Saturday 0116 Monday 1331 Tuesday 1125 Thursday 0010 Monday 0439 Friday 2128 Monday 1342 Saturday 2109 Saturday 2144 Saturday 1709 Wednesday 0741 Saturday 0157 Sunday 1744 Friday 1025 Saturday 0212 Saturday 1719 Tuesday 2303 Sunday 1708 Saturday 2047 Tuesday 1326 Thursday 1839 Thursday 2056 Wednesday 1443 Thursday 0907 Tuesday 0634 Friday 1905 Friday 0404 Thursday 2038 Wednesday 0419 Tuesday 1325 Monday 0537 Tuesday 1708 Monday 1503 Monday 2200 Wednesday 2126 Tuesday 2221 Thursday 2048 Monday 1910 Wednesday 0032 Monday 0823 Thursday 2305 Sunday 2216 Saturday 2029 Friday 0800 Monday 0841 Tuesday 0834 Monday 0407 Monday 0439 Tuesday 0737 Wednesday 1902 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- SUNDAY: 112 139 121 127 126 105 104 119 116 124 113 132 119 118 116 105 117 124 117 108 140 112 113 113 MONDAY: 123 118 131 131 105 102 129 109 134 116 124 116 116 111 118 124 127 133 111 126 128 123 105 110 TUESDAY: 111 132 134 113 128 108 141 119 108 122 115 106 126 118 127 117 117 125 90 103 130 108 97 102 WEDNESDAY: 138 134 117 121 91 123 118 125 104 142 130 130 101 137 120 120 128 121 124 125 117 111 114 136 THURSDAY: 118 126 127 111 124 111 121 116 135 134 110 90 113 120 143 100 127 109 126 108 118 126 107 132 FRIDAY: 129 138 117 127 116 105 114 126 126 145 110 110 120 117 125 127 133 121 118 130 105 113 108 127 SATURDAY: 106 128 116 113 114 119 120 110 111 138 138 105 122 130 101 126 108 133 111 133 133 93 92 107 CHAPTER 8 – Multidimensional Arrays 123

  9. MATRIX OPERATIONS // SquareMatrix.h // // The SquareMatrix class implements a square matrix of double // // values, with functionality to add, subtract, multiply (both // // scalar and matrix multiplication), invert, input, and output. // #ifndefSQUARE_MATRIX_H #include <fstream> #include <iomanip> using namespace std; const intMAX_SIZE = 10; // CLASS DEFINITION classSquareMatrix { public: SquareMatrix(); SquareMatrix(intmatrixSize); SquareMatrix(constSquareMatrix &sm); intgetSize(); SquareMatrix invert(); double operator () (int row, int column); friendSquareMatrixoperator + (const SquareMatrix &smA, constSquareMatrix &smB); friendSquareMatrixoperator - (constSquareMatrix &smA, constSquareMatrix &smB); friendSquareMatrixoperator * (constSquareMatrix &smA, constSquareMatrix &smB); friendSquareMatrixoperator * (double coefficient, constSquareMatrix &sm); friendostream& operator << (ostream &outputFile, constSquareMatrix &sm); friendistream& operator >> (istream &inputFile, SquareMatrix &sm); private: int size; double matrix[MAX_SIZE][MAX_SIZE]; }; Two-dimensional arrays may be used to represent matrices, making it possible to implement linear algebra problems. CHAPTER 8 – Multidimensional Arrays 124

  10. // CLASS IMPLEMENTATION // Default Constructor: Initializes // the SquareMatrix to an identity // matrix of the maximum size. SquareMatrix::SquareMatrix() { int row, col; size = MAX_SIZE; for (row = 0; row < MAX_SIZE; row++) for (col = 0; col < MAX_SIZE; col++) if (row == column) matrix[row][col] = 1.0; else matrix[row][col] = 0.0; return; } //Initializing Constructor: Initializes // the SquareMatrix the an identity // matrix of the parameterized size. SquareMatrix::SquareMatrix(intmatrixSize) { int row, col; size = matrixSize; for (row = 0; row < matrixSize; row++) for (col = 0; col < matrixSize; col++) if (row == col) matrix[row][col] = 1.0; else matrix[row][col] = 0.0; return; } // Copy Constructor: Copies the // parameterized SquareMatrix. SquareMatrix::SquareMatrix(constSquareMatrix &sm) { int row, col; size = sm.size; for (row = 0; row < size; row++) for (col = 0; col < size; col++) matrix[row][col] = sm.matrix[row][col]; return; } // Size Accessor Function: Merely // returns the SquareMatrix size value. intSquareMatrix::getSize() { return size; } CHAPTER 8 – Multidimensional Arrays 125

  11. // Invert Member Function: By applying the same operations to an identity matrix as to // the original matrix, placing the latter in reduced row echelon form results in // transforming the former into the inverse matrix of the original matrix. SquareMatrixSquareMatrix::invert() { int row, column, index; double temp, scaleFactor; SquareMatrixcopyMatrix(size); SquareMatrixinverseMatrix(size); for (row = 0; row < size; row++) for (column = 0; column < size; column++) copyMatrix.matrix[row][column] = matrix[row][column]; // Convert the original matrix to reduced row echelon form, performing // the same operations on what will become the inverse matrix. for (row = 0; row < size; row++) { // If this diagonal element is zero, swap rows with // one in which this column's value is not zero. if (copyMatrix.matrix[row][row] == 0.0) { index = row + 1; while (copyMatrix.matrix[index][row] == 0.0) index++; for (column = 0; column < size; column++) { temp = copyMatrix.matrix[row][column]; copyMatrix.matrix[row][column] = copyMatrix.matrix[index][column]; copyMatrix.matrix[index][column] = temp; temp = inverseMatrix.matrix[row][column]; inverseMatrix.matrix[row][column] = inverseMatrix.matrix[index][column]; inverseMatrix.matrix[index][column] = temp; } } CHAPTER 8 – Multidimensional Arrays 126

  12. // Scale the row so its diagonal element is one. scaleFactor = copyMatrix.matrix[row][row]; for (column = 0; column < size; column++) { copyMatrix.matrix[row][column] /= scaleFactor; inverseMatrix.matrix[row][column] /= scaleFactor; } // Subtract a scaled version of the row from all // other rows until the only non-zero element in // the column is the one in the row's diagonal slot. for (index = 0; index < size; index++) if ( (index != row) && (copyMatrix.matrix[index][row] != 0.0) ) { scaleFactor = copyMatrix.matrix[index][row]; for (column = 0; column < size; column++) { copyMatrix.matrix[index][column] -= copyMatrix.matrix[row][column] * scaleFactor; inverseMatrix.matrix[index][column] -= inverseMatrix.matrix[row][column] * scaleFactor; } } } returninverseMatrix; } When converting a matrix into reduced row echelon form, if the same operations are simultaneously applied to an identity matrix, the identity matrix is transformed into the inverse of the original matrix. CHAPTER 8 – Multidimensional Arrays 127

  13. // Overloaded Parentheses Operator: Returns the matrix value at the slot corresponding // to the parameterized indices. (Returns zero if those indices are invalid.) doubleSquareMatrix::operator () (int row, int column) { if ( (row >= 0) && (row < size) && (column >= 0) && (column < size) ) return matrix[row][column]; else return 0.0; } // Overloaded Addition Operator: Returns a SquareMatrix that is the sum of the two SquareMatrix // parameter values (using the smaller of their two sizes if they differ in size). SquareMatrixoperator + (constSquareMatrix &smA, constSquareMatrix &smB) { SquareMatrixnewMatrix; int row, column; newMatrix.size = (smA.size < smB.size) ? smA.size : smB.size; for (row = 0; row < newMatrix.size; row++) for (column = 0; column < newMatrix.size; column++) newMatrix.matrix[row][column] = smA.matrix[row][column] + smB.matrix[row][column]; returnnewMatrix; } // Overloaded Subtraction Operator: Returns a SquareMatrixthatis the difference of the two // SquareMatrix parameter values (using the smaller of their two sizes if they differ in size). SquareMatrixoperator - (constSquareMatrix &smA, constSquareMatrix &smB) { SquareMatrixnewMatrix; int row, column; newMatrix.size = (smA.size < smB.size) ? smA.size : smB.size; for (row = 0; row < newMatrix.size; row++) for (column = 0; column < newMatrix.size; column++) newMatrix.matrix[row][column] = smA.matrix[row][column] - smB.matrix[row][column]; returnnewMatrix; } CHAPTER 8 – Multidimensional Arrays 128

  14. // Overloaded Multiplication Operator: Returns a SquareMatrix that // is the product of the two parameterized SquareMatrix values // (using the smaller of their two sizes if they differ in size). SquareMatrixoperator * (constSquareMatrix &smA, constSquareMatrix &smB) { SquareMatrixnewMatrix; int row, column, index; newMatrix.size = (smA.size < smB.size) ? smA.size : smB.size; for (row = 0; row < newMatrix.size; row++) for (column = 0; column < newMatrix.size; column++) { newMatrix.matrix[row][column] = 0.0; for (index = 0; index < newMatrix.size; index++) newMatrix.matrix[row][column] += smA.matrix[row][index] * smB.matrix[index][column]; } returnnewMatrix; } // Overloaded Multiplication Operator: Returns a SquareMatrix // that is the product of the parameterized scalar value and // the parameterized SquareMatrix value. SquareMatrixoperator * (double coefficient, constSquareMatrix &sm) { SquareMatrixnewMatrix; int row, column; newMatrix.size = sm.size; for (row = 0; row < newMatrix.size; row++) for (column = 0; column < newMatrix.size; column++) newMatrix.matrix[row][column] = coefficient * sm.matrix[row][column]; returnnewMatrix; } CHAPTER 8 – Multidimensional Arrays 129

  15. // Overloaded Output Operator: Outputs the parameterized SquareMatrix // to the parameterized output file, using 10 digits for each value // in the matrix and inserting a linefeed after each row. ostream& operator << (ostream &outputFile, constSquareMatrix &sm) { int row, column; outputFile.setf(ios::fixed); outputFile.setf(ios::showpoint); outputFile.precision(3); for (row = 0; row < sm.size; row++) { for (column = 0; column < sm.size; column++) outputFile << setw(10) << sm.matrix[row][column]; outputFile << endl; } returnoutputFile; } // Overloaded Input Operator: Inputs the parameterized SquareMatrix // from the parameterized input file, reading the elements of one // row at a time. istream& operator >> (istream &inputFile, SquareMatrix &sm) { int row, column; inputFile >> sm.size; for (row = 0; row < sm.size; row++) for (column = 0; column < sm.size; column++) inputFile >> sm.matrix[row][column]; returninputFile; } #define SQUARE_MATRIX_H #endif CHAPTER 8 – Multidimensional Arrays 130

  16. // This driver program merely tests the SquareMatrix class functionality. #include <iostream> #include <fstream> #include "SquareMatrix.h" using namespace std; void main() { SquareMatrixmatA, matB, invA; ifstream sourceFile1, sourceFile2; ofstreamdestinationFile; inti; sourceFile1.open("MatrixData1.txt"); sourceFile1 >> matA; sourceFile1.close(); sourceFile2.open("MatrixData2.txt"); sourceFile2 >> matB; sourceFile2.close(); destinationFile.open("MatrixResults.txt"); destinationFile << "MATRIX A:" << endl << matA << endl; destinationFile << "MATRIX B:" << endl << matB << endl; destinationFile << "DIAGONAL OF B: "; for (i = 0; i < matB.getSize(); i++) destinationFile << matB(i, i) << " "; destinationFile << endl << endl; destinationFile << "SUM (A+B):" << endl << matA + matB << endl; destinationFile << "DIFFERENCE (A-B):" << endl << matA - matB << endl; destinationFile << "MATRIX PRODUCT (A*B):" << endl << matA * matB << endl; destinationFile << "SCALAR PRODUCT (5*B):" << endl << 5 * matB << endl; invA = matA.invert(); destinationFile << "INVERSE OF A:" << endl << invA << endl; destinationFile << "PRODUCT OF A AND ITS INVERSE:" << endl << matA * invA << endl; destinationFile.close(); return; } CHAPTER 8 – Multidimensional Arrays 131

  17. MATRIX A: 3.500 2.400 1.000 -4.600 -1.700 0.000 4.700 2.100 6.600 4.800 -5.000 1.600 2.100 -8.500 3.500 -7.400 MATRIX B: -6.400 1.200 6.100 -4.700 0.100 7.400 -0.500 5.300 4.200 0.000 8.400 -8.500 5.300 -7.100 6.600 1.200 DIAGONAL OF B: -6.400 7.400 8.400 1.200 SUM (A+B): -2.900 3.600 7.100 -9.300 -1.600 7.400 4.200 7.400 10.800 4.800 3.400 -6.900 7.400 -15.600 10.100 -6.200 DIFFERENCE (A-B): 9.900 1.200 -5.100 0.100 -1.800 -7.400 5.200 -3.200 2.400 4.800 -13.400 10.100 -3.200 -1.400 -3.100 -8.600 MATRIX PRODUCT (A*B): -42.340 54.620 -1.810 -17.750 41.750 -16.950 42.970 -29.440 -54.280 32.080 6.420 38.840 -38.810 -7.840 -2.380 -93.550 SCALAR PRODUCT (5*B): -32.000 6.000 30.500 -23.500 0.500 37.000 -2.500 26.500 21.000 0.000 42.000 -42.500 26.500 -35.500 33.000 6.000 INVERSE OF A: -0.027 0.120 0.169 0.088 0.147 -0.004 -0.046 -0.102 0.057 0.197 0.013 0.023 -0.149 0.132 0.107 0.018 PRODUCT OF A AND ITS INVERSE: 1.000 0.000 0.000 0.000 0.000 1.000 -0.000 -0.000 -0.000 0.000 1.000 -0.000 0.000 -0.000 -0.000 1.000 MatrixResults.txt MatrixData1.txt 4 3.5 2.4 1.0 -4.6 -1.7 0.0 4.7 2.1 6.6 4.8 -5.0 1.6 2.1 -8.5 3.5 -7.4 MatrixData2.txt 4 -6.4 1.2 6.1 -4.7 0.1 7.4 -0.5 5.3 4.2 0.0 8.4 -8.5 5.3 -7.1 6.6 1.2 CHAPTER 8 – Multidimensional Arrays 132

  18. CHAPTER 9 Input and Output Streams • Escape Sequences • Formatting Output CHAPTER 9 – Input and Output Streams 133

  19. ESCAPE SEQUENCES Because of the syntax rules of C++, some characters require special escape sequences to accomplish output. #include <iostream> #include <fstream> #include <string> using namespace std; const intNBR_SEQUENCES = 6; const char SEQUENCE[] = { '\a', '\n', '\t', '\\', '\'', '\"' }; const string SEQUENCE_LABEL[] = { "ALERT (\\a): ", "NEW LINE (\\n): ", "HORIZONTAL TAB (\\t): ", "BACKSLASH (\\\\): ", "SINGLE QUOTATION MARK (\\'): ", "DOUBLE QUOTATION MARK (\\\"): " }; voidprintHeader(); voidoutputSequence(int index); void main() { inti; printHeader(); for (i = 0; i < NBR_SEQUENCES; i++) outputSequence(i); } CHAPTER 9 – Input and Output Streams 134

  20. voidprintHeader() { cout << " ESCAPE SEQUENCE TESTER" << endl; cout << " ----------------------" << endl; cout << "This application tests each of the C++ escape" << endl; cout << "sequences by verifying that you are ready for" << endl; cout << "the next one, and then using it in output six" << endl; cout << "times, with every time preceded by an ordinal" << endl; cout << "number (1 through 6). " << endl << endl; } voidoutputSequence(int index) { char whatever; inti; cout << "Enter any character to proceed " << "to the next escape sequence: "; cin >> whatever; cout << endl << SEQUENCE_LABEL[index] << endl; for (i = 1; i <= 6; i++) cout << i << SEQUENCE[index]; cout << "(end of sequence)" << endl << endl << endl; } CHAPTER 9 – Input and Output Streams 135

  21. CHAPTER 9 – Input and Output Streams 136

  22. FORMATTING OUTPUT #include <iostream> #include <iomanip> #include <fstream> #include <string> using namespace std; const string INPUT_FILE_NAME = "Source.txt"; const string LEFT_OUTPUT_FILE_NAME = "LeftOutput.txt"; const string RIGHT_OUTPUT_FILE_NAME = "RightOutput.txt"; intgetInputSize(); voidloadArray(double list[], intlistSize); voidleftFormatOutput(double list[], intlistSize); voidrightFormatOutput(double list[], intlistSize); voidoutputArray(ofstream &file, double list[], intlistSize); void main() { double* nbrList; int size; size = getInputSize(); nbrList = new double[size]; loadArray(nbrList, size); leftFormatOutput(nbrList, size); rightFormatOutput(nbrList, size); delete[] nbrList; return; } With the inclusion of the iomanip library, additional output formatting options are made available. CHAPTER 9 – Input and Output Streams 137

  23. intgetInputSize() { int count = 0; double value; ifstreamsourceFile; sourceFile.open(INPUT_FILE_NAME.c_str()); sourceFile >> value; while (!sourceFile.eof()) { count++; sourceFile >> value; } sourceFile.close(); return count; } voidloadArray(double list[], intlistSize) { int index; ifstreaminputFile; inputFile.open(INPUT_FILE_NAME.c_str()); for (index = 0; index < listSize; index++) inputFile >> list[index]; inputFile.close(); return; } voidleftFormatOutput(double list[], intlistSize) { ofstreamoutputFile; outputFile.open(LEFT_OUTPUT_FILE_NAME.c_str()); outputFile.setf(ios::left); outputFile.setf(ios::fixed); outputFile.setf(ios::showpoint); outputFile.precision(4); outputArray(outputFile, list, listSize); outputFile.close(); return; } voidrightFormatOutput(double list[], intlistSize) { ofstreamoutputFile; outputFile.open(RIGHT_OUTPUT_FILE_NAME.c_str()); outputFile.setf(ios::right); outputFile.setf(ios::fixed); outputFile.setf(ios::showpoint); outputFile.precision(2); outputArray(outputFile, list, listSize); outputFile.close(); return; } CHAPTER 9 – Input and Output Streams 138

  24. voidoutputArray(ofstream &file, double list[], intlistSize) { int index; file << setw(10) << "COLUMN 1" << setw(10) << "COLUMN 2" << setw(10) << "COLUMN 3" << endl; for (index = 0; index < listSize; index++) { file << setw(10) << list[index]; if (index % 3 == 2) file << endl; } return; } LeftOutput.txt Source.txt COLUMN 1 COLUMN 2 COLUMN 3 3.1416 98.6000 2.7183 0.5772 1.6180 6.0221 -2.0023 -3.8261 -273.1500 3.14159 98.6 2.71828 0.5772156649 1.61803398874989 6.02214199 -2.0023193 -3.82608545 -273.15 RightOutput.txt COLUMN 1 COLUMN 2 COLUMN 3 3.14 98.60 2.72 0.58 1.62 6.02 -2.00 -3.83 -273.15 CHAPTER 9 – Input and Output Streams 139

  25. CHAPTER 10 Introduction to Numerical Methods • Roots of Functions • Statistics • Numerical Differentiation • Numerical Integration CHAPTER 10- Introduction to Numerical Methods 140

  26. ROOTS OF FUNCTIONS One common numerical method using derivatives is Newton’s Method, which attempts to locate an approximation to a root of a function. (x0, f(x0) x1 = x0 – f(x0)/f(x0) x0 (First Guess) x2 = x1 – f(x1)/f(x1) (x1, f(x1) CHAPTER 10 – Introduction to Numerical Methods 141

  27. NEWTON’S METHOD //////////////////////////////////////////////////////////////////////// // Polynomial.h - Poloynomial Class Definition // // Uses a dynamic array to store the coefficients of a polynomial. // // Includes member functions for taking the derivative and evaluating // // at specific x-values, as well as a friend output operator. // //////////////////////////////////////////////////////////////////////// #ifndefPOLYNOMIAL_H #include <iostream> #include <fstream> using namespace std; // THE CLASS DEFINITION // class Polynomial { public: Polynomial(); Polynomial(int deg); Polynomial(const Polynomial &poly); voidsetDegree(int exponent); voidsetCoefficient(intexponent, doublecoeff); Polynomial derivative() const; doubleevaluateAt(double x) const; friendostream& operator << (ostream &outputFile, const Polynomial &poly); private: int degree; double* coefficient; }; CHAPTER 10 – Introduction to Numerical Methods 142

  28. // THE CLASS IMPLEMENTATION // // Default Constructor: Sets Polynomial's // degree to meaningless negative value. Polynomial::Polynomial() { degree = -1; } // Initializing Constructor: Sets Polynomial's // degree to parameterized value, resetting all // coefficients to zero. Polynomial::Polynomial(int deg) { degree = deg; if (degree >= 0) coefficient = newdouble[degree + 1]; } // Copy Constructor: Duplicates parameterized Polynomial. Polynomial::Polynomial(const Polynomial &poly) { int exponent; degree = poly.degree; if (degree >= 0) { coefficient = new double[degree + 1]; for (exponent = 0; exponent <= degree; exponent++) coefficient[exponent] = poly.coefficient[exponent]; } } CHAPTER 10 – Introduction to Numerical Methods 143

  29. // Mutator Function setDegree: Resets Polynomial's degree, // resetting all coefficients to zero at the same time. void Polynomial::setDegree(int exponent) { int power; if (degree >= 0) delete[] coefficient; degree = exponent; if (exponent >= 0) { coefficient = newdouble[degree + 1]; for (power = 0; power <= degree; power++) coefficient[power] = 0.0; } return; } // Mutator Function setCoefficient: Resets the coefficient of // the Polynomial's term with the parameterized exponent to the // parameterized value (if possible). void Polynomial::setCoefficient(intexponent, doublecoeff) { if ( (exponent >= 0) && (exponent <= degree) ) coefficient[exponent] = coeff; return; } CHAPTER 10 – Introduction to Numerical Methods 144

  30. // Member Function derivative: Generates new Polynomial that // is the derivative function for the existing Polynomial. Polynomial Polynomial::derivative() const { Polynomial derivPoly; int power; // If the Polynomial is meaningless, so is its derivative. if (degree < 0) derivPoly.setDegree(-1); // If the Polynomial is constant, its derivative is zero. else if (degree == 0) { derivPoly.setDegree(0); derivPoly.setCoefficient(0, 0.0); } // If the Polynomial is "regular", differentiate in the normal way. else { derivPoly.setDegree(degree - 1); for (power = 1; power <= degree; power++) derivPoly.setCoefficient(power - 1, power * coefficient[power]); } returnderivPoly; } CHAPTER 10 – Introduction to Numerical Methods 145

  31. // Member Function evaluateAt: Calculates and returns the // Polynomial's value at the parameterized x-value (if possible). double Polynomial::evaluateAt(double x) const { double result = 0.0; int power; if (degree >= 0) { result = coefficient[degree]; for (power = degree - 1; power >= 0; power--) result = result * x + coefficient[power]; } return result; } // Output Operator: Outputs the parameterized Polynomial (in standard // polynomial format) to the parameterized output file. ostream& operator << (ostream &outputFile, const Polynomial &poly) { int power; // Only output if the Polynomial is meaningful. if (poly.degree >= 0) { // Skip all of the leading terms with zero coefficients. power = poly.degree; while ( (poly.coefficient[power] == 0.0) && (power > 0) ) power--; // Output the leading term and its coefficient properly. if (poly.coefficient[power] == -1.0) outputFile << "-"; else if (poly.coefficient[power] != 1.0) outputFile << poly.coefficient[power]; CHAPTER 10 – Introduction to Numerical Methods 146

  32. if (power == 1) outputFile << "x"; else if (power > 1) outputFile << "x^" << power; // Cycle through the rest of the polynomial's terms. power--; while (power >= 0) { // Skip all terms with zero coefficients. if (poly.coefficient[power] != 0.0) { // Handle positive and negative coefficients // as sums and differences. if (poly.coefficient[power] < 0.0) { outputFile << " - "; if (poly.coefficient[power] != -1.0) outputFile << -poly.coefficient[power]; } else { outputFile << " + "; if ( (poly.coefficient[power] != 1.0) || (power == 0) ) outputFile << poly.coefficient[power]; } if (power == 1) outputFile << "x"; else if (power > 1) outputFile << "x^" << power; } power--; } } returnoutputFile; } #define POLYNOMIAL_H #endif CHAPTER 10 – Introduction to Numerical Methods 147

  33. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NewtonsMethod.cpp - Driver Program To Implement Newton's Method // // this driver program employs the Polynomial class to query the // // user for a polynomial (its degree and coefficients) and a guess // // of a possible root. It then uses Newton's Method to iteratively // // locate an actual root for the polynomial (if possible). // ///////////////////////////////////////////////////////////////////// #include <iostream> #include <cmath> #include "Polynomial.h" using namespace std; Polynomial retrievePolynomial(); doubleretrieveRootGuess(const Polynomial &poly); voidoutputNewtonsResults(const Polynomial &poly, doublecurrentX); // The main function sets the output format, and then supervises the // retrieval of the polynomial and the user's root guess, followed by // the application of Newton's Method to approximate an actual root. void main() { Polynomial poly; doublecurrentXGuess; cout.setf(ios::fixed); cout.precision(3); poly = retrievePolynomial(); currentXGuess = retrieveRootGuess(poly); outputNewtonsResults(poly, currentXGuess); } CHAPTER 10 – Introduction to Numerical Methods 148

  34. // The retrievePolynomial queries the user for polynomial information // (the degree and coefficients of the polynomial). Polynomial retrievePolynomial() { Polynomial poly; int exponent; intpowerIndex; doublecoeff; cout << "Specify the degree of the polynomial's leading coefficient: "; cin >> exponent; while (exponent < 0.0) { cout << "Negative degrees are unacceptable. Please try again: "; cin >> exponent; } poly.setDegree(exponent); for (powerIndex = exponent; powerIndex >= 0; powerIndex--) { cout << "Specify the coefficient of the "; switch (powerIndex) { case 0: cout << "constant"; break; case 1: cout << "linear"; break; case 2: cout << "quadratic"; break; case 3: cout << "cubic"; break; default: cout << "x^" << powerIndex; break; } cout << " term: "; cin >> coeff; poly.setCoefficient(powerIndex, coeff); } return poly; } CHAPTER 10 – Introduction to Numerical Methods 149

  35. // Function retrieveRootGuess queries the user for an initial // estimate of a root for the parameterized polynomial. double retrieveRootGuess(const Polynomial &poly) { doublepossibleRoot; cout << "Specify a first \"guess\" at a root for the polynomial" << endl << "f(x) = " << poly << " : "; cin >> possibleRoot; returnpossibleRoot; } // The outputNewtonsResults function runs Newton's Method on the parameterized // polynomial, starting at the parameterized x-value, and outputs the ordered // pairs of values that occur until either the sequence converges (i.e., the // current x-value produces a near-zero y-value) or it diverges (i.e., // consecutive x-values start getting further and further apart). voidoutputNewtonsResults(const Polynomial &poly, doublecurrentX) { const double EPSILON = 0.000001; Polynomial derivPoly = poly.derivative(); doublecurrentY = poly.evaluateAt(currentX); doublepreviousX; doublederivY; doublepreviousError = 100000.0; doublecurrentError; boolacceptableError = true; bool converged = false; CHAPTER 10 – Introduction to Numerical Methods 150

  36. // Keep iterating as long as the current x-value doesn't // produce a y-value adequately close to zero, or until // consecutive x-values start getting further apart. while ( (acceptableError) && (!converged) ) { cout << "x = " << currentX << " f(x) = " << currentY << endl; derivY = derivPoly.evaluateAt(currentX); // Newton's Method requires dividing by the derivative, so if // the derivative equals zero, conclude that the method failed. if (derivY == 0.0) acceptableError = false; else { previousX = currentX; currentX -= currentY / derivY; currentY = poly.evaluateAt(currentX); converged = (fabs(currentY) < EPSILON); currentError = fabs(currentX - previousX); acceptableError = (currentError < previousError); previousError = currentError; } } // If the iterative process terminates due to // convergence, then the approximate root is output. // Otherwise, the failure of the method is reported. if (converged) cout << endl << "Newton's Method estimates a root for the polynomial" << endl << "f(x) = " << poly << " at x = " << currentX << endl << endl; else cout << "Newton's Method failed for this polynomial and this initial guess. " << endl << endl; return; } CHAPTER 10 – Introduction to Numerical Methods 151

  37. CHAPTER 10 – Introduction to Numerical Methods 152

  38. STATISTICS One common statistical approach, the least-squares method, uses linear regression to determine the closest line that fits a set of points. CHAPTER 10 – Introduction to Numerical Methods 153

  39. LINEAR REGRESSION //////////////////////////////////////////////////// // Statistics.h // // Contains various statistics utility functions. // //////////////////////////////////////////////////// #ifndefSTATISTICS_H #include <cmath> // The minimum function returns the smallest value in the parameterized array. double minimum(const double val[], int size) { doubleminVal = val[0]; int index; for (index = 1; index < size; index++) if (val[index] < minVal) minVal = val[index]; returnminVal; } // The maximum function returns the largest value in the parameterized array. double maximum(const double val[], int size) { doublemaxVal = val[0]; int index; for (index = 1; index < size; index++) if (val[index] > maxVal) maxVal = val[index]; returnmaxVal; } CHAPTER 10 – Introduction to Numerical Methods 154

  40. // The mean function returns the average of all // values in the parameterized array. double mean(const double list[], int size) { int index; double sum = 0.0; for (index = 0; index < size; index++) sum += list[index]; if (size == 0) return 0.0; else return sum / size; } // The standardDeviation function returns the standard // deviation of all values in the parameterized array. doublestandardDeviation(const doublelist[], int size) { double average = mean(list, size); doublesumSquareDiff = 0.0; int index; for (index = 0; index < size; index++) sumSquareDiff += pow( (list[index] - average), 2 ); if (size == 0) return 0.0; else return sqrt( sumSquareDiff / size ); } CHAPTER 10 – Introduction to Numerical Methods 155

  41. // The linearRegression function calculates the slope and y-intercept // of the line that most closely approximates (via the least-squares // approach) the set of points represented by the two parallel arrays. voidlinearRegression(const double x[], const double y[], int size, double &slope, double &yIntercept) { doubleaverageX = mean(x, size); doubleaverageY = mean(y, size); double numerator = 0; double denominator = 0; int index; for (index = 0; index < size; index++) { numerator += (x[index] - averageX) * (y[index] - averageY); denominator += pow( (x[index] - averageX), 2 ); } if (denominator == 0.0) slope = 0.0; else slope = numerator / denominator; yIntercept = averageY - slope * averageX; return; } #define STATISTICS_H #endif CHAPTER 10 – Introduction to Numerical Methods 156

  42. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ImageGrid.h // // This header file includes the definition and implementation of the ImageGrid // // class, which represents a two-dimensional image composed of characters. // ////////////////////////////////////////////////////////////////////////////////// #ifndefIMAGE_GRID_H #include <iostream> #include <fstream> #include <string> using namespace std; const intGRID_SIZE = 50; // THE CLASS DEFINITION // classImageGrid { public: ImageGrid(); voidxyToRowColumn(double x, double y, int &row, int &column); voidinitializeGrid(double xMin, doublexMax, double yMin, doubleyMax); voidmarkGrid(double x, double y, char symbol); voiddrawLine(doubleslope, doubleintercept, charsymbol); friendostream& operator << (ostream &outputFile, constImageGrid &image); private: char grid[GRID_SIZE][GRID_SIZE]; doublelowerBoundX; doubleupperBoundX; doublelowerBoundY; doubleupperBoundY; }; CHAPTER 10 – Introduction to Numerical Methods 157

  43. // THE CLASS IMPLEMENTATION // // Default Constructor - Initializes grid to all blanks. // ImageGrid::ImageGrid() { int row, column; for (row = 0; row < GRID_SIZE; row++) for (column = 0; column < GRID_SIZE; column++) grid[row][column] = ' '; } // Member function xyToRowColumn: Determines // the grid's row/column pair that corresponds // to the parameterized x- and y-coordinates. voidImageGrid::xyToRowColumn(double x, double y, int &row, int &column) { column = int( (x - lowerBoundX) * (GRID_SIZE - 1) / (upperBoundX - lowerBoundX) ); row = int( (upperBoundY - y) * (GRID_SIZE -1) / (upperBoundY - lowerBoundY) ); return; } CHAPTER 10 – Introduction to Numerical Methods 158

  44. // Member function initializaGrid: Uses the parameterized x- and y-coordinate limits // to determine where in the image the coordinate axes should be placed. voidImageGrid::initializeGrid(doublexMin, doublexMax, doubleyMin, doubleyMax) { intzeroRow, zeroColumn, row, column; lowerBoundX = xMin; upperBoundX = xMax; lowerBoundY = yMin; upperBoundY = yMax; xyToRowColumn(0.0, 0.0, zeroRow, zeroColumn); if ( (0 <= zeroColumn) && (zeroColumn < GRID_SIZE ) ) for (row = 0; row < GRID_SIZE ; row++) grid[row][zeroColumn] = '|'; if ( (0 <= zeroRow) && (zeroRow < GRID_SIZE ) ) for (column = 0; column < GRID_SIZE ; column++) grid[zeroRow][column] = '-'; if ( (0 <= zeroColumn) && (zeroColumn < GRID_SIZE ) && (0 <= zeroRow) && (zeroRow < GRID_SIZE ) ) grid[zeroRow][zeroColumn] = '+'; return; } // Member function markGrid: Determines the row and column associated // with the parameterized x/y coordinates, and then marks the grid // slot with that row and that column with the parameterized symbol. voidImageGrid::markGrid(double x, double y, char symbol) { int row, column; xyToRowColumn(x, y, row, column); if ( (0 <= column) && (column < GRID_SIZE) && (0 <= row) && (row < GRID_SIZE) ) grid[row][column] = symbol; } CHAPTER 10 – Introduction to Numerical Methods 159

  45. // Member function drawLine: Uses the parameterized slope and y-intercept to // mark the grid points comprising the corresponding line. If the slope // is steep, the iteration is row-by-row, otherwise, it's column-by-column. voidImageGrid::drawLine(double slope, double intercept, char symbol) { int row, column, index; double x, y; if ( (slope <= 1.0) && (slope >= -1.0) ) for (index = 0; index < 2*GRID_SIZE; index++) { x = lowerBoundX + index * (upperBoundX - lowerBoundX) / (2*GRID_SIZE - 1); y = slope * x + intercept; xyToRowColumn(x, y, row, column); if ( (0 <= column) && (column < GRID_SIZE) && (0 <= row) && (row < GRID_SIZE) ) grid[row][column] = symbol; } else for (index = 0; index < 2*GRID_SIZE; index++) { y = lowerBoundY + index * (upperBoundY - lowerBoundY) / (2*GRID_SIZE - 1); x = (y - intercept) / slope; xyToRowColumn(x, y, row, column); if ( (0 <= column) && (column < GRID_SIZE) && (0 <= row) && (row < GRID_SIZE) ) grid[row][column] = symbol; } } CHAPTER 10 – Introduction to Numerical Methods 160

  46. // Output Operator: Overloaded output // operator that outputs the grid to // the parameterized output file. ostream& operator << (ostream &outputFile, constImageGrid &image) { int row, column; for (row = 0; row < GRID_SIZE; row++) { for (column = 0; column < GRID_SIZE; column++) outputFile << image.grid[row][column]; outputFile << endl; } returnoutputFile; } #define IMAGE_GRID_H #endif ///////////////////////////////////////////////////////////////////////////// // LinearRegression.cpp // // This driver program generates a grid of characters that graphs a set of // // 2D points (from a user-specified input file) and the least-squares line // // that most closely fits that set of points. // ///////////////////////////////////////////////////////////////////////////// #include <iostream> #include<fstream> #include <string> #include "Statistics.h" #include "ImageGrid.h“ using namespace std; voidretrievePairs(double* &x, double* &y, int &size); voidcountPairs(string fileName, int &size); voidoutputResults(const double x[], const double y[], int n, double m, double b); voidsetXYBoundaries(const double x[], const double y[], int n, double &lowX, double &highX, double &lowY, double &highY); CHAPTER 10 – Introduction to Numerical Methods 161

  47. // The main function coordinates the retrieval of the data set // of ordered pairs, the least-square-fit, and the final output. void main() { double* xValue, yValue; intlistSize; doublelineSlope, intercept; retrievePairs(xValue, yValue, listSize); linearRegression(xValue, yValue, listSize, lineSlope, intercept); outputResults(xValue, yValue, listSize, lineSlope, intercept); return; } // The retrievePairs function fills the pair of parallel arrays // with ordered pairs of data from a user-specified file. voidretrievePairs(double* &x, double* &y, int &size) { string fileName; ifstreaminputFile; int index; cout << "Specify the name of the file containing the ordered pairs: "; cin >> fileName; countPairs(fileName, size); x = new double[size]; y = new double[size]; inputFile.open(fileName.c_str()); for (index = 0; index < size; index++) { inputFile >> x[index]; inputFile >> y[index]; } inputFile.close(); return; } CHAPTER 10 – Introduction to Numerical Methods 162

  48. // The countPairs function determines the number // of ordered pairs of values that exist in the // input file with the parameterized name. voidcountPairs(string fileName, int &size) { ifstreaminputFile; doublenewX, newY; inputFile.open(fileName.c_str()); size = 0; inputFile >> newX; while (!inputFile.eof()) { inputFile >> newY; size++; inputFile >> newX; } inputFile.close(); return; } // The outputResults function sets up and completes // an image grid by marking it with then points in // the parameterized pair of parallel arrays, and // by drawing the least-squares line-fit. voidoutputResults(const double x[], const double y[], int n, double m, double b) { doublelowX, highX, lowY, highY; ImageGrid image; int index; setXYBoundaries(x, y, n, lowX, highX, lowY, highY); image.initializeGrid(lowX, highX, lowY, highY); image.drawLine(m, b, '*'); for (index = 0; index < n; index++) image.markGrid(x[index], y[index], 'O'); cout << "The resulting linear regression: " << endl; cout << image << endl; } CHAPTER 10 – Introduction to Numerical Methods 163

  49. // The setXYBoundaries function finds lower and upper bounds for // the parameterized lists of x-values and y-values, adjusting // these boundaries so the gap between them is identical. voidsetXYBoundaries(const double x[], const double y[], int n, double &lowX, double &highX, double &lowY, double &highY) { lowX = minimum(x, n); highX = maximum(x, n); lowY = minimum(y, n); highY = maximum(y, n); if ( highX - lowX > highY - lowY ) { highY = (highY + lowY) / 2 + (highX - lowX) / 2; lowY = (highY + lowY) / 2 - (highX - lowX) / 2; } else { highX = (highX + lowX) / 2 + (highY - lowY) / 2; lowX = (highX + lowX) / 2 - (highY - lowY) / 2; } return; } CHAPTER 10 – Introduction to Numerical Methods 164

  50. points.txt 35.9 24.1 27.7 15.6 22.8 19.2 17.4 10.6 12.1 10.2 10.8 7.5 9.2 5.7 4.3 9.0 0.2 1.7 -1.5 4.4 -7.0 -10.1 -12.6 -7.9 -19.8 -15.3 CHAPTER 10 – Introduction to Numerical Methods 165