CSCI 159 Lab 4 exercises

Lab 4 is due prior to the start of your lab 5's on Nov. 3rd/5th

As usual, there are two halves (first half in basic.cpp and second half in lab4.cpp), where the second half is an extended independent design section.

Hopefully most people complete nearly the entire first half of lab 4 in their scheduled lab section on Oct. 13th/15th.

Here is the collection of new C++ syntax elements we'll be using for lab4.


Follow our usual setup process

  1. Log in, open a browser, go to the lab4 page, open a terminal window:
    (see lab 2 if you need a refresher on any of the steps)

  2. get lab4:
    make -f make159 csci159/lab4

  3. Go into your lab4 directory and begin the edit/compile/test/submit routine: As with previous labs, you'll see that the two .cpp files are nearly empty to start with.


First half: the basics of loops and booleans (to be done in basic.cpp)

We'll be using the string and iostream libraries for basic.cpp, and writing three functions:

We'll need several constants as well:

The main routine will:
  1. call skipThis("step one") and check the return value to see if the user wishes to skip step one. If skipThis returns false then we do want to try stepOne here, so the test will look something like
    if (!skipThis("step one")) {
    If the user didn't skip then we want to call stepOne and store/print the value it returns (so we can check it did return the value correctly).

  2. do similarly for step two, but here the body of the if can simply call stepTwo.

The starting code will thus look something like this (with empty implementations of the three functions down at the bottom):

// set which characters we'll for yes/no
const char YES = 'Y';
const char NO = 'N';

// set the maximum number of input characters to clear on broken input
const int LineLen = 80;

 // how many estimates we'll go through in our square root calculations
const int AccuracyIterations = 10;

// asks the user if they want to skip a section (Y or N)
//    repeats the question (using do while) until they enter Y or y or N or n
// returns true if they want to skip, false otherwise
bool skipThis(string section);

// stepOne uses a while loop to get a number greater than one from the user then returns it
// (repeats until a valid value is supplied)
float stepOne();

// stepTwo uses a for loop to approximate the square root of a number
// (each pass through the loop gets a better approximation than the previous pass,
//  stepTwo uses stepOne to get the number)
void stepTwo();

int main()
{
   // run the two steps, giving the user chances to skip either or both
   if (!skipThis("step one by itself")) {
      float positiveNum;
      positiveNum = stepOne();
      cout << "Your number was " << positiveNum << endl;
      cout << "End of step one" << endl;
   }
   if (!skipThis("step two")) {
      stepTwo();
   }
}

bool skipThis(string section)
{
   return true; // <== we'll replace this when we write the real version of the function
}

float stepOne()
{
   return 0; // <== we'll replace this when we write the real version of the function
}

void stepTwo()
{
}

Writing skipThis

(This code will replace the "return true;" we had in skipThis originally.)

This is meant to prompt the user to enter Y or N (for yes or no) and return true if they said Y or false if they said N.

We'll use a do-while loop to repeat until they enter something valid, and we'll convert the character they enter to uppercase (so they can enter y or n in addition to Y or N).

The nice thing about char input is that it cannot cause cin to fail, so we don't need to worry about cin.fail, cin.clear, and cin.ignore.

In this case, we'll use a boolean variable (validAnswer) to keep track of whether or not we've seen valid input from the user. This will be set to false initially (since we haven't seen any input from the user yet) and will be changed to true once we have valid input.

Thus our loop structure is something like
char skipOrNot;  // the variable where we'll store the user input
bool validAnswer = false; // do we have valid input yet?
do {
   // get the user to enter their character, store it in skipOrNot
   // convert it to uppercase
   // if it's yes then we can simply return true (we're done, they want to skip)
   // otherwise if it's no then we can set validAnswer to true
   //    (we have a valid answer, asking not to skip)
   // otherwise we can display an error/try again message
} while (!validAnswer);
return false; // we got out of the loop because they said No to skipping

Remember you have the constants YES and NO, be sure to use those rather than hard-coding 'Y' and 'N' inside your function.

Converting to uppercase is done by the 'toupper' function (from the cctype library, which is included for you by the string library), e.g.
myvar = toupper(myvar); // where myvar is a char variable

Writing stepOne

(This code will replace the "return 0;" we had in stepOne originally.)

This will look more like our earlier exercises where a function gets and checks a number, but we're doing it in a while loop instead of using recursion.

We'll need a float to store the user number in, and (like in skipThis) we'll use a boolean variable to keep track of whether or not we've obtained a valid value from the user.

Our loop logic can thus look something like:
float finalNum;
bool validNumber = false;
while (!validNumber) {
   // do your cout and cin to get the user's input
   // if cin.failed then give them an error/try again message
   //     (but no recursive call this time, since the loop will take care of repeating)
    // otherwise if the number is <= 1 give them an error/try again message
    //    (again, no recursive call in this lab)
    // otherwise set validNumber to true, so the loop will stop
    //    when it gets checked at the beginning of the next pass
}
return finalNum;

Writing stepTwo

We'll need variables to keep track of: To get started, we need to call stepOne and assign its return value to originalNum, and as our initial lower/upper bounds on the square root of that we can use 1 and originalNum (e.g. if originalNum is 12 we can safely assume its square root is somewhere in the range 1..12).

Our for loop will then go through each of the estimates, getting more accurate each time:
for (estimateNum = 1; estimateNum <= AccuracyIterations; estimateNum++) {
    // set our new estimate to be (lowerBound + upperBound)/2
    // set square to be (estimate * estimate)
    // if square is bigger than originalNum
    //    then set upperBound = estimate
    // otherwise if square is smaller than originalNum
    //    then set lowerBound = estimate
    // otherwise
    //    tell the user we got the exact answer (!)
    //    and 'break' from the loop
}
output our final estimate, square, and the originalNum we were trying to compute the root of

Sample run

The output below shows a sample run where the user chose to skip step one and entered 12 as the number to compute the root of. (User input illustrated using bold italics here just for clarity)

Do you want to skip step one by itself (Y or N): y
Do you want to skip step two (Y or N): n
Please enter a number greater than 1.0: 12
Guess number 1: 6.5
Guess number 2: 3.75
Guess number 3: 2.375
Guess number 4: 3.0625
Guess number 5: 3.40625
Guess number 6: 3.57812
Guess number 7: 3.49219
Guess number 8: 3.44922
Guess number 9: 3.4707
Guess number 10: 3.45996
Our final estimate was 3.45996, whose square is 11.9713 (aiming for 12)

As always, check you've followed code standards and do a make submit


Second half: design and implementation problem with loops (to be done in lab4.cpp)

We're still a little before the 314th day of the year, but for this problem you'll be writing a program that makes multiple attempts to approximate the value of Pi, using a simulation technique and random number generator described below.

Estimating pi by random dart throwing

Requirement: all repetition must be done using loops. No recursion at all is permitted in lab4.cpp.

Your desired program behaviour

Your program will do the following:

Sample run

(The sample run below shows user input in bold italics just for the sake of clarity.)

Please enter the desired sample size (number of points) as an integer (e.g. 217): foo
Sorry, that was not an integer: please try again

Please enter the desired sample size (number of points) as an integer (e.g. 217): -1
Sorry, the value needs to be greater than zero: please try again

Please enter the desired sample size (number of points) as an integer (e.g. 217): ick
Sorry, that was not an integer: please try again

Please enter the desired sample size (number of points) as an integer (e.g. 217): blah
Sorry, that was not an integer: please try again

Please enter the desired sample size (number of points) as an integer (e.g. 217): -3
Sorry, the value needs to be greater than zero: please try again

Please enter the desired sample size (number of points) as an integer (e.g. 217): -4
Sorry, the value needs to be greater than zero: please try again

Please enter the desired sample size (number of points) as an integer (e.g. 217): 90567

Of the 90567 points tested, 70922 landed in the unit circle,
giving a pi estimate of 3.13235

Experiment with different sample sizes and see how the estimate gets better as the sample size increases.

(Don't be surprised if you have to get into sizes in the millions before consistently seeing it accurate to a few decimal places.)

As always, check you've followed code standards and do a make submit