go to start Ex W4
|home |print view |recent changes |changed September 15, 2017 |
exact
|You are 54.81.59.211 <- set your identity!

Sections: 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 | Extra exercises | Retro: Ansi Terminal Control | Retro: Pocket Calculator | Experiment: Timing Parameter Passing Variation |

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.

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.

Tipp: Have a look at functions defined in <cctype> (character-type) and the available algorithms in <algorithm> (std::lexicographical_compare).

 

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 ^

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 ^

Retro: Ansi Terminal Control ^

Caution: the CDT-console is not ANSI compatible. Use the terminal window of your Linux VM for visual tests.

Here is information about the escape codes that allow you to control the cursor and color in a terminal window.

http://ascii-table.com/ansi-escape-sequences.php

The "Esc" escape character is '\033' or decimal value of char(27).

All escape sequences start with the string "\033[". You should place the following functions in a separate namespace Ansi.

Ansi.h (incomplete, needs additions)

namespace Ansi {
        
        std::string const ESCAPE{"\033["};
	std::string Clear();
	std::string ForeColor(unsigned color);
	std::string BackColor(unsigned color);
	std::string Bold();
        std::string AttributeOff();
	std::string Pos(unsigned l, unsigned c);
	std::string Home();
	std::string Up(unsigned n);
	std::string Down(unsigned n);
	std::string Right(unsigned n);
	std::string Left(unsigned n);
}

Here is an example of a possible implemenation of one of the functions

std::string Ansi::Pos(unsigned l, unsigned c) { 
    return ESCAPE + std::to_string(l) + ";" + std::to_string(c) + "H"; 
}
Here are some CUTE test cases (to be completed):
#include "Ansi.h"
#include "cute.h"
#include "ide_listener.h"
#include "cute_runner.h"
void testClear(){
	ASSERT_EQUAL("\033[2J",Ansi::Clear());
}
void testForeColorWhite() {
	ASSERT_EQUAL("\033[37m",Ansi::ForeColor(Ansi::white));
}
void testBAckColorBlack(){
	ASSERT_EQUAL("\033[40m",Ansi::BackColor(Ansi::black));
}
void testBold(){
	ASSERT_EQUAL("\033[1m",Ansi::Bold());
}
void testAttrOff(){
	ASSERT_EQUAL("\033[0m",Ansi::AttributeOff());
}
void testPosXY(){
	ASSERT_EQUAL("\033[2;3H",Ansi::Pos(2,3));
}
void testHome(){
	ASSERT_EQUAL("\033[0;0H",Ansi::Home());
}
void testUp(){
	ASSERT_EQUAL("\033[2A",Ansi::Up(2));
}
void testDown(){
	ASSERT_EQUAL("\033[3B",Ansi::Down(3));
}
void testRight(){
	ASSERT_EQUAL("\033[4C",Ansi::Right(4));
}
void testLeft(){
	ASSERT_EQUAL("\033[5D",Ansi::Left(5));
}
void runAllTests(int argc, char const *argv[]){
	cute::suite s;
	s.push_back(CUTE(testForeColorWhite));
	s.push_back(CUTE(testClear));

	s.push_back(CUTE(testBAckColorBlack));
	s.push_back(CUTE(testBold));
	s.push_back(CUTE(testAttrOff));
	s.push_back(CUTE(testPosXY));
	s.push_back(CUTE(testHome));
	s.push_back(CUTE(testUp));
	s.push_back(CUTE(testDown));
	s.push_back(CUTE(testLeft));
	s.push_back(CUTE(testRight));
	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);
}
Create two Eclipse projects, one with your Ansi library and one with the unit tests for it. And you might create a third Eclipse project for an executable that demonstrates the working of your Ansi library to you if you run it in the terminal window.

Retro: Pocket Calculator ^

Use the library with Ansi terminal control functions to create a pocket calculator in retro style. For each result output, move the cursor to the upper left corner of the terminal window and print the seven segment digits there in green (or red) on a black background.

The input of the next calculation happens two lines below the 2 segment digit display.

Can you also implement the possibility of chained calculations, so that a line can also start with an operator and just a single operand, but takes the previous result displayed as its first operand? When a line consists of a single operand only, take that as the new value to be displayed. This provides more of a feeling of a pocket calculator.

Variation: Implement your retro pocket calculator for floating point calculation. Provide a fixed number of digits plus a two-digit exponent for larger/smaller numbers (1.00000E+05). Figure out, how and where to place a decimal . in the simulated seven segment digit output as well as a minus sign.

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 September 15, 2017 |
exact
|You are 54.81.59.211 <- set your identity!

Ex W4
go to start