go to start Ex W4
|home |print view |recent changes |changed October 22, 2017 |
exact
|You are 54.196.47.128 <- set your identity!

Sections: Reading C++ Code | 1 ''Testat-Exercise 1'': Calculator with Retro Style Output | 2 Word List | 3 Function countingToLower | 4 Function-Value Table | 5 Experiment: Look into Object files (Optional) | Extra exercises | Experiment: Timing Parameter Passing Variation |

Reading C++ Code ^

This exercise combines various C++ code elements you should be able to at least understand and explain with your current knowledge.

Read the program and try to figure out what it does. The following topics occur in the example:

#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>

namespace Games {

struct FizzBuzz {
  void run(unsigned n, std::ostream & out) {
    std::ostream_iterator<std::string> outIter{out, "\n"};
    auto gen = [this] {
      value++;
      std::string result{};
      if (value % 3 == 0) {
        result += "Fizz";
      }
      if (value % 5 == 0) {
        result += "Buzz";
      }
      if (result.empty()) {
        result = std::to_string(value);
      }
      return result;
    };
    std::generate_n(outIter, n, gen);
  }
private:
  int value{};
};

}

int main(int argc, char **argv) {
  Games::FizzBuzz fb{};
  fb.run(15, std::cout);
}

Note: This example is artificial, some parts of it are not solved in the shortest possible way.

1 Testat-Exercise 1: Calculator with Retro Style Output ^

Hand in time is Monday Oct 23 2017, 12:00 (noon) (CEST)

Hand in all your source files attached to a single email to thomas.corbat@hsr.ch, peter.sommerlad@hsr.ch . NO ZIP, NO object files, NO eclipse project.

Use your libraries from the previous weeks to create a simple pocket calculator simulation. Allow the user to enter a calculation using two integers and an infix operator symbol on a single line and display the result of the calculation in a large way using your seven segment display simulation from last week. For the underlying calculation use your function calc(). Read the input line by line (std::getline()) and interpret each line as a calculation (operand operator operand).

6*7
    - 
| |  |
 -  -
  ||  
    - 
1*0
 - 
| |
   
| |
 - 

If the format is wrong or the calculation is invalid, display "Error". You can define additional "digits" in your seven-segment display for the letters "E", "r" and "o" to make the Error message fit your retro-style.

Hint: Use your knowledge about exceptions from the lecture to handle error cases properly!

1/0
 -             
|              
 -  -  -  -  - 
|  |  |  | ||  
 -        -    

2 Word List ^

Write a program wlist that reads all words (as defined by std::string's input operator >>) from the standard input and produce a sorted list of all occurring words, where each word only is printed once. What data structure and algorithms are you using? Do not write your own loops nor use std::for_each.

Hints:

 

3 Function countingToLower ^

Implement a function countingToLower that makes the following test cases pass.

#include "cute.h"
#include "ide_listener.h"
#include "xml_listener.h"
#include "cute_runner.h"

void lowerFirstCharacter() {
	std::string str("Hello!");
	ASSERT_EQUAL(1, countingToLower(str));
	ASSERT_EQUAL("hello!", str);
}

void lowerSeveralCharacters() {
	std::string str("Hello World, its ME!");
	ASSERT_EQUAL(4, countingToLower(str));
	ASSERT_EQUAL("hello world, its me!", str);
}

void lowerNone() {
	std::string str("no uppercase characters here");
	ASSERT_EQUAL(0, countingToLower(str));
	ASSERT_EQUAL("no uppercase characters here", str);
}

void lowerAll() {
	std::string str("LOL");
	ASSERT_EQUAL(3, countingToLower(str));
	ASSERT_EQUAL("lol", str);
}

void lowerEmpty() {
	std::string str("");
	ASSERT_EQUAL(0, countingToLower(str));
	ASSERT_EQUAL("", str);
}

void umlautsAreNotChanged() {
	std::string str("ÄÖÜ");
	ASSERT_EQUAL(0, countingToLower(str));
	ASSERT_EQUAL("ÄÖÜ", str);
}
void runAllTests(int argc, char const *argv[]){
	cute::suite s;
	s.push_back(CUTE(lowerFirstCharacter));
	s.push_back(CUTE(lowerSeveralCharacters));
	s.push_back(CUTE(lowerNone));
	s.push_back(CUTE(lowerAll));
	s.push_back(CUTE(lowerEmpty));
	s.push_back(CUTE(umlautsAreNotChanged));
	cute::xml_file_opener xmlfile(argc,argv);
	cute::xml_listener<cute::ide_listener<> >  lis(xmlfile.out);
	cute::makeRunner(lis,argc,argv)(s, "AllTests");
}

int main(int argc, char const *argv[]){
    runAllTests(argc,argv);
}

4 Function-Value Table ^

Create a library with a function printFunctionTable that takes an ostream, a beginning and end value of type double, a number of steps, and a function as arguments. The function will produce a table of function values as follows by dividing the range given into n steps and prints the function results as follows: (start=1.0, end=3.0, steps=3, f(x) = [](double x){return x*x;})

x    1.0 2.0 3.0  
f(x) 1.0 4.0 9.0
You might use a loop for the solution, or store the n used x values in a std::vector<double> first, by using algorithm generate_n.

Demonstrate your function beyond your unit tests by a main() function that displays the functions std::sin(x), std::cos(x), std::tan(x) for x from 0 to pi in 19 steps (10 degrees each).

5 Experiment: Look into Object files (Optional) ^

To understand details of C++ linking and libraries, we will look into the structure of object and library files. On Linux (Unix, MacOS, MinGW on Windows) exists the program nm that prints the content of binary object files, libraries or executables on standard output. Use that command in a terminal and check out its output if you give one of your own compiled files as input. You will find those in the Debug/ folder in your project directories.

Even if you do not understand all details of its output try to find the encoding of your (overloaded) functions within a object file or library of your calc and sevensegment object files and libraries.

 nm hello.o | c++filt

In most cases you do not need to care about these details, because the linker will handle that for you. However, the experiment can improve your understanding of the compilation model and the (limited) meta information that object files carry. Unfortunately, there is no easy access from a program to the meta information the linker needs to know about. But the experiment will help you understand linker error messages better in the future.


Extra exercises ^

Experiment: Timing Parameter Passing Variation ^

The following code frame uses a function that creates a large vector and pass this large vector 100 times by value, effectively copying it to a function. To avoid having an optimizer optimize it away the function itself returns a random element from the given vector.

#include <vector>
#include <string>
#include <iostream>
#include <iomanip>
#include <chrono>

using testdata=std::vector<std::string>;

std::string pass_by_value(testdata v){
	size_t index = std::rand()%v.size();
	return v[index];
}
void copying_source_outside(){
	testdata v(1000000," ");
	for (int i = 0; i < 100; i++)
	{
		auto res = pass_by_value(v);
	}
}

std::chrono::microseconds time_func(void  (f)()){
	using namespace std::chrono;
	high_resolution_clock clock { };
	auto start=clock.now();
		f();
	auto end = clock.now();
	return duration_cast<microseconds>(end - start);
} 
int main(){
	auto elapsed = time_func(copying_source_outside).count();
	std::cout << "source_outside :" << elapsed << " us\n";
}


|home |print view |recent changes |changed October 22, 2017 |
exact
|You are 54.196.47.128 <- set your identity!

Ex W4
go to start