# Exercise 4-3

What happens if we rewrite the previous program to allow values up to but not including 1000 but neglect to change the arguments to setw? Rewrite the program to be more robust in the face of changes that allow i to grow without adjusting the setw arguments.

# Solution

Though there are many ways to solve this problem, below is the solution strategy that I use, with the aim of enhanced flexibility:

1. Obtain the asymmetric range [m,n) from the user with the condition of n > m. In other words, m is the startNumber. n – 1 is the endNumber.
2. Compute the number of elements within this asymmetric range as n – m. This is equivalent to the number of loops required (or number of rows to output).
3. Create a function getStreamWidth that will be used to automatically compute the maximum width required for column 1 (the list of numbers), and column 2 (the square of column 1). This function is capable of dealing with both negative and non-negative input values.
4. Have a for loop to output column 1 and 2 using the corresponding column stream widths computed upfront (step 3 above).

## The Project

I have decided to partition the program as follows – for practice sake.

### C++ Source Files

• main.cpp – this is the first program that is run during the implementation phase.
• getStreamWidth.cpp – contains all functions relating to obtaining the stream widths.

This diagram below shows what the Code::Block Management Tree look like after successful creation of these files.

The actual content of the source and header files are documented in the following sections.

### Source Files

#### main.cpp

#include <iostream>
#include <ios>
#include <iomanip>
#include <algorithm>
#include "getStreamWidth.h"

using std::cout;  // <iostream>
using std::cin;   // <iostream>
using std::endl;  // <iostream>
using std::streamsize;  // <ios>
using std::setw;  // <iomanip>
using std::max;  // <algorithm>

int main()
{
#include <iostream>
#include <ios>
#include <iomanip>
#include <algorithm>
#include "getStreamWidth.h"

using std::cout;  // <iostream>
using std::cin;   // <iostream>
using std::endl;  // <iostream>
using std::streamsize;  // <ios>
using std::setw;  // <iomanip>
using std::max;  // <algorithm>

int main()
{
// display program intro message
cout << "***********************************************************\n"
<< "*** This program computes the square of the numbers     ***\n"
<< "*** in the asymmetric range [m,n).                      ***\n"
<< "*** (Limitation: please ensure n > m)                   ***\n"
<< "*** e.g. [3,7) contains elements 3, 4, 5, 6 (but not 7) ***\n"
<< "***********************************************************";
cout << endl;

// ask user to supply m
cout << "Enter m: ";
int m;
cin >> m;

// ask user to supply n
cout << "Enter n: ";
int n;
cin >> n;

// ensure m and n are input correctly. If not, exit program.
if (n <= m)
{
cout << "Please make sure n > m";
return 1;
}

// initialise value
const int startNumber = m;    // first output integer
const int endNumber = n - 1;  // last output integer
const int numLoops = n - m;  // number of rows to output

// find the maxwidth for column 1 and 2
const streamsize col1Width = max(getStreamWidth(startNumber), getStreamWidth(endNumber));
const streamsize col2Width = max(getStreamWidth(startNumber * startNumber), getStreamWidth(endNumber * endNumber));

// display a summary
cout << "Asymmetric range: [" << m << "," << n << ")" << endl;
cout << "Number of rows = " << numLoops << endl;
cout << "Column 1 width = " << col1Width << " | Column 2 width = " << col2Width << endl;

// get ready to print report
int y = startNumber;
for (int i = 0; i != numLoops; ++i)
{
cout << setw(col1Width) << y << setw(col2Width) << (y * y) << setw(0) << endl;
++y;
}
return 0;
}


#### getStreamWidth.cpp

#include <ios>

using std::streamsize;

// return the required streamsize to fit a particular integer number
streamsize getStreamWidth(int number)
{

streamsize numDigits;

// initialise numDigits and number depending on whether value is positive / negative.
// If negative, require at least 2 spaces to fit the leading empty space string and the negative sign
// If positive, require at least 1 space to fit the leading empty space string
if (number < 0)
{
numDigits = 2;
number *= -1;
}
else numDigits = 1;

// numDigits is the number of divisions required to make number approaches zero (plus leading space and sign)
// i.e. this is equivalent to the total stream width required
while (number != 0)
{
++numDigits;
number /= 10;
}

return numDigits;
}


#### getStreamWidth.h

#ifndef GUARD_GETSTREAMWIDTH_H
#define GUARD_GETSTREAMWIDTH_H

std::streamsize getStreamWidth(int number);

#endif // GUARD_GETSTREAMWIDTH_H


# Test Results

## Asymmetric range [-3, 4)

***********************************************************
*** This program computes the square of the numbers     ***
*** in the asymmetric range [m,n).                      ***
*** (Limitation: please ensure n > m)                   ***
*** e.g. [3,7) contains elements 3, 4, 5, 6 (but not 7) ***
***********************************************************
Enter m: -3
Enter n: 4
Asymmetric range: [-3,4)
Number of rows = 7
Column 1 width = 3 | Column 2 width = 2
-3 9
-2 4
-1 1
0 0
1 1
2 4
3 9


## Asymmetric range [995,1006)

***********************************************************
*** This program computes the square of the numbers     ***
*** in the asymmetric range [m,n).                      ***
*** (Limitation: please ensure n > m)                   ***
*** e.g. [3,7) contains elements 3, 4, 5, 6 (but not 7) ***
***********************************************************
Enter m: 995
Enter n: 1006
Asymmetric range: [995,1006)
Number of rows = 11
Column 1 width = 5 | Column 2 width = 8
995  990025
996  992016
997  994009
998  996004
999  998001
1000 1000000
1001 1002001
1002 1004004
1003 1006009
1004 1008016
1005 1010025


## Asymmetric range [-1005,-996)

***********************************************************
*** This program computes the square of the numbers     ***
*** in the asymmetric range [m,n).                      ***
*** (Limitation: please ensure n > m)                   ***
*** e.g. [3,7) contains elements 3, 4, 5, 6 (but not 7) ***
***********************************************************
Enter m: -1005
Enter n: -996
Asymmetric range: [-1005,-996)
Number of rows = 9
Column 1 width = 6 | Column 2 width = 8
-1005 1010025
-1004 1008016
-1003 1006009
-1002 1004004
-1001 1002001
-1000 1000000
-999  998001
-998  996004
-997  994009


## Asymmetric range [0,1000)

***********************************************************
*** This program computes the square of the numbers     ***
*** in the asymmetric range [m,n).                      ***
*** (Limitation: please ensure n > m)                   ***
*** e.g. [3,7) contains elements 3, 4, 5, 6 (but not 7) ***
***********************************************************
Enter m: 0
Enter n: 1000
Asymmetric range: [0,1000
Number of rows = 1000
Column 1 width = 4  Column 2 width = 7
0      0
1      1
2      4
...
993 986049
994 988036
995 990025
996 992016
997 994009
998 996004
999 998001


# Reference

Koenig, Andrew & Moo, Barbara E., Accelerated C++, Addison-Wesley, 2000

## 5 thoughts on “Accelerated C++ Solution to Exercise 4-3”

1. Anonymous says:

on line 63 & 64 on main.cpp, why did you use streamsize instead of just assigning the value of the function to an int? Like so:

int x = max(getStreamWidth(startNumber)……)

wouldnt this still work?

1. Johnny says:

I used streamsize instead of int because the function getStreamWidth() returns a streamsize type output. So assigning a streamsize value to a streamsize x seem to make sense to me. Moreover it avoids the need for C++ to implicitly convert a streamsize type value into a int type value. Nevertheless, it turns out that both int and streamsize types are both signed. see this article. So in this case, my guess is, int x might work as well as streamsize x. Try and see!

2. Salik says:

why do you have two mains in main.cpp?

3. Mr Tap says:

The solution here is unnecessarily complicated considering the assignment, and it is way beyond the student level. The ‘enhanced flexibility’ only means that the example is incomprehensible for a student at this level. Besides taking into account negatives when we are dealing with squares (always positive )is another pointless complication. just make sure the 1st column is wide enough to have room for the minus sign.

This is really all it takes, and it can be done with what the student is supposed to know thus far: (those mathematically inclined can replace the loop in columnwidth with ln(max)…)

 columnwidth(int n){ int w=0; while (n>0){ n /= 0; // same as n=n/10 ++w; } return w+2; } 

[…]

int max=1000;
for (int i=0; i<max+1;++i)
cout << setw(columwidth(max)) << i
<< setw(columnwidth(maxmax) << ii << endl;

4. Mr Tap says:

line 4 is supposed to be n /= 10