EngLinks APSC 142 Workshop Part 1 (Solutions) 1 Variable Types, Declarations, and Expressions Constants Constants using a directive are defined like so: #define VARIABLENAME 12345 Anytime VARIABLENAME is referred to, the program will substitute 12345. Data Types char: Stores characters as ASCII codes (‘a’, ‘b’, ‘c’, etc.) int: Stores integers (1, 2345, -1235, etc.) long: Stores larger integers (1234518348284, 18384872776463, -383847274742, etc.) float: Stores floating point numbers (1.5, 4948.00, -382.583, etc.) When mixing datatypes, such as assigning a float value (i.e. 43.23) to an integer variable, the compiler will convert the value’s type to match the variable’s type. In this case, 43.23 would be converted to an integer, and become 43, before it is assigned and stored. You can also cast variables, like so: int k = (int)43.23; which will convert 43.23 to an integer before it is stored. Declaring Variables Variables can be declared like so: int variable_name; And then initialized like so: variable_name = 12345; Or, declared and initialized in the same line like so: int variable_name = 12345; Expressions Using operators and operands, we can combine values and assign them to a variable. These expressions can include variables and numerical values, as well as any of the following: +,-,*,/,%, (, ). Expressions follow the BEDMAS (brackets, exponents, divide, multiply, add, subtract) order of operations. For example, the following code would assign k the value of 25. int i = 100; int k = (i + 100) / 8; We can also use assignment operators such as +=, -=, *=, or /=. The expression k = 100 * k; is the same as k *= k;. Additionally, we can simply use ++, -- after a variable like so: 2 k++; to increment a variable by one. Using the -- decrements the variable by one. Screen output Text can be displayed on the EV3 robot’s screen like so: displayTextLine(4, “Distance away is: %d”, distance); where the first argument is the line you wish to display the output on, the second argument is the display string, and the third argument is a variable you wanted to display. The %d is a format specifier, which basically specifies that it wants to display distance as an integer. Other format specifiers include %f, %c, and %e, among others. Question 1: In the box below, show the screen output that would be produced by this program (i.e. account for integer arithmetic and any rounding truncation): task main() { int k; float x; x = 13.7; k = x; displayTextLine(0, “%d, %0.1f”, k, x); k = k/3; x = k*3; displayTextLine(1, “%d, %0.1f”, k, x); } Answer 1: 13, 13.7 4, 12.0 Question 2: In the box below, show the screen output that would be produced by this program (i.e., account for integer arithmetic and any rounding truncation): task main() { int i = 5, j = 2, k; float x = 6.3, y; displayTextLine(0, “%d, %0.3f”, i, x); k = i/j; y = (float)i/(float)j; displayTexxtLine(1, “%d, %0.3f”, k, y); } 3 Answer 2: 5, 6.300 2, 2.500 Question 3: In the box below, show the screen output that would be produced by the following program. task main() { int i, j, temp; i = 1; j = 2; displayTextLine(0, "i=%d, j=%d", i, j); temp = i; i = j; j = temp; displayTextLine(1, "i=%d, j=%d", i, j); } Answer 3: i=1, j=2 i=2, j=1 4 Conditionals Condition statements are either true or false, and can be used like so: if (distance > 25) { //do stuff } In the above example, the program will only execute whatever is between the brackets, on the condition that the distance variable is greater than 25. “>” is a relational operator, relating the variable to the number. Other relational operators include: ==, <=, >=, !=, <. You can use other conditions as well, like so: if(distance > 25) { //do stuff } else if(distance < 10) { //do other stuff } else { //do other other stuff } In the above example, it will check the first condition, and if that doesn’t hold, it will check the second example. If neither holds, it will automatically execute whatever is in the “else” block. You can also use logical operators such as || (or), or && (and) to check for more conditions like so: if(distance > 25 && distance < 100) { //do stuff } Switch-case statements can also be used, which look like this: switch(counter) { case 0: //do stuff break; case 1: //do other stuff break; } In the above example, counter is a variable that the switch-case statement will check. Based on the value of counter, different parts of the code will execute. In this case, if counter is 0, the block directly below case 0 will execute. If counter is 1, the block directly below case 1 will execute. Keep in mind that the break; command is important and must be placed at the end of each “case” block. 5 Loops There are three types of loops in C: while, do/while, and for. While loops A while loop is used like so: while(condition) { //do stuff } A while loop will check the condition, and execute the block of code within the brackets if the condition is true. The loop will continue checking and executing the code until the condition is false, in which case the loop ends. Do-while loops A do/while loop is used like so: do { //do stuff } while(condition) In the case of a do-while loop, the block of code between the brackets will be executed first, before the condition is checked. Note that this is different from a while loop, in that a while loop checks the condition first, before executing the code. For loops A for loop is used like so: for(int k = 0; k < 100; k++) { //do stuff } where the first expression initializes a variable that will be used like a counter, the second expression specifies the termination condition, and the last expression specifies how the variable is modified after each loop. Note that in the example above, the variable is declared and initialized within the loop. It can also be declared outside the loop like so: int k; for(k = 0; k < 100; k++) { //do stuff } 6 Question 4: In the box below, show the screen output that would be produced by this program: task main() { int nums[5] = {1,7,5,9,6}; int j; int highsum = 0; int lowsum = 0; for(j=0; j<5; j++) { if(nums[j]<=5) lowsum += nums[j]; else highsum += nums[j]; } displayTextLine(0, "low sum = %d", lowsum); displayTextLine(1, "high sum = %d", highsum); } Answer 4: low sum = 6 high sum = 22 Question 5: Write a program that calculates values of the polynomial y = 3x3 – 5x2 + 100x – 17 at x = 0, x=0.2, x=0.4, … , x=4.0 (that is, for values of x separated by 0.2 between a start value of 0 and an end value of 4.0). The y-values that are between -17 and +60, inclusive, are considered mid-range; the values that are greater than 60 are considered high and the values that are lower than -17 are considered low. Your program should determine and then display how many of the x-values in [0,4] evaluate to high y-values, how many evaluate to mid-range y-values and how many evaluate to low y-values. 7 Answer 5: task main() { int low = 0, mid = 0, high = 0; float y; float x = 0; for(x = 0; x <= 4; x += 0.2) { y = (3*x*x*x) - (5*x*x) + (100*x) - 17; if(y >= -16 && y <= 60) mid++; else if(y > 60) high++; else low++; } displayTextLine(0, "high values: %d", high); displayTextLine(1, "mid values: %d", mid); displayTextLine(2, "low values: %d", low); } Question 6: Write a program that calculates values of the polynomial y = 9x3 – 2x2 + 44x – 15 at x = 0, x = 0.4, x = 0.8, … , x = 4.0 (that is, for values of x separated by 0.4 between a start value of 0 and an end value of 4.0). The y-values that are between -5 and +20, inclusive, are considered typical and the values that are greater than 60 or less than -20 are considered extreme. Your program should determine and then display how many of the x-values in [0,4] evaluate to typically –values and how many evaluate to extreme y-values. Answer 6: task main() { int y, x; int typ = 0; ext = 0; for(x = 0; x <= 4; x += 0.4) { y = (9*x*x*x) - (2*x*x) + 44*x) - 15; if(y >= -5 && y <= 20) typ++; else if(y,-20||y>60); ext++; } displayTextLine(0, "Typical = %d", typ); displayTextLine(1, "Extreme = %d", ext); } 8 Arrays 1-D Arrays Arrays are used to store multiple objects of the same type, and can be thought of as a list. By using an array, you can store related values in one variable without having to declare a new variable for each object. For example: float marks[5]; declares an array of 5 variables of type int, that are all contained under the variable “marks”. To access an object stored in an array, use the variable name and its index like so: marks[3]; The above line would access the 4th element in the array. This is because arrays are zero-indexed, meaning the first element in the array is stored at index 0. You can also initialize an array like so: float marks[5] = {80.32, 63.71, 84.1, 77.0, 86.4}; which would store the objects like this: marks[0] marks[1] marks[2] marks[3] marks[4] 80.32 63.71 84.1 77.0 86.4 You can fill an array using a loop like so: int values[5]; for(int i = 0; i < 5; i++) { marks[i] = i*5; } which is usually good if you want to fill an array with numbers with a regular pattern. You can also access elements with a loop like so: int values[5] = {123, 48, 2, 88, 9}; for(int i = 0; i < 5; i++) { displayTextLine(i, "The value is: %d", values[i]); } 2-D Arrays 2-D arrays are very similar to 1-D arrays, except it can be thought of as more like a matrix or a table, than a list. 2-D arrays can be declared like so: int values[3][3]; and initialized like so: int values[3][3] = {{1, 4, 6}, {5, 7, 9}, {2, 8, 0}}; 9 which would store the objects like this: values[x][0] values[x][1] values[x][2] values[0][x] 1 4 6 values[1][x] 5 7 9 values[2][x] 2 8 0 You can fill an array using a loop like so: int values[3][3]; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { values[i][j] = i*j; } } which again, is usually good if you want to fill an array with numbers with a regular pattern. You can also access elements with a loop like so: int values[3][3]; int sum = 0; int i, j; for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { sum += values[i][j]; } } 10 Question 7: In the box below, show the screen output that would be produced by this program: task main() { int matrix[4][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}; int i, j, line = 0; for(i = 1; i < 4; i = i + 2) { for(j = 0; j < 4; j = j + 2); { displayTextLine(line, "%d", matrix[i][j]); line++; } } } Answer 7: 5 7 13 15 Question 8: In the box below, show the screen output tha would be produced by the following program. task main() { int i; int arr[6]; } for(i = 0; i < 6; i++) { arr[i] = i+i; } for(i=0; i < 6; i+=3) { displayTextLine(i, "array[%d] = %d", i, arr[i+1]); } 11 Answer 8: array[0] = 2 array[3] = 8 Functions A function is a subprogram with its own declarations and statements, that is typically meant to perform a specific task. The advantage of using functions is that they can be used multiple times in the same program, and can be quite versatile if written properly. For example, you could write a drive function for the EV3 robots, that accepts speed and duration arguments, allowing you to call the drive function multiple times to drive for different durations at different speeds. Functions can accept many parameters, but can only return at most one value. A function can be declared like so: int add_numbers(int num1, int num2); In this example, the function returns an integer, is named “add_numbers”, and takes two integers as parameters. A function’s parameters can be declared with both variable types and names, or just variable types. The above line is sometimes called a function prototype, and would be placed at the top of your program, before task main(). This is because the C compiler reads through the program line by line, top to bottom, and if you call a function in your task main() but haven’t declared it yet, the compiler won’t know what you’re talking about and return an error. To actually write a function, you would leave the function prototype at the beginning of your program, and then define it after the task main() like so: int add_numbers(int num1, int num2) { int sum; sum = num1 + num2; return sum; } Note that there is a semicolon after the function prototype, but no semicolon in your function declaration. In the above example, the add_numbers function takes two integers as parameters, adds them together, and then returns the result. Note the“return sums;” line, which specifies that the function will return the value of sum, back to wherever the function was called. At least one return line is necessary in any function that has been declared to return a value. Multiple return lines can be placed in different loops or conditions, allowing the function to return a different result based on different circumstances. Once the program reaches a return line, it automatically ends the function and goes back to wherever the function was called. Parameters can be of any type, and you can return any type you choose. You can even choose not to return anything at all, in which case you would return type “void” like so: void drive(int speed, int duration); Note that in a void function, there is no return line. To call a function, you would do it like so: 12 task main() { int x = 3; int y = 5; int z; } z = add_numbers(x, y); Using the add_numbers function from above, this function call would call add_numbers, passing x as num1 and y as num2. Sum would then be returned and stored in z. Note that x and y are not altered by the function. You can also pass by reference. If we alter our add_numbers function like so: void add_numbers(int num1, int num2, int &sum) { int sum; sum = num1 + num2; } And call it like so: task main() { int x = 3; int y = 5; int z; add_numbers(x, y, &z); } x and y will not be altered, but z will. This is because adding the ampersand in front of the variable passes the address of the variable, instead of the value stored in the variable. When we pass z by reference to add_numbers, sum has the same address as z. As a result, when we execute the line sum = num1 + num2, the result is stored in both sum, as well as z. Variable Scope The scope of a variable defines where the variable is accessible. A variable declared within a function, called a local variable, is only accessible within that function. Conversely, a variable declared outside any function is called a global variable, and can be accessed anywhere. For example, when you declare a variable “x” within a function definition, your task main() will not recognize it if you try to access it. In fact, if you were to declare a variable “x” within your task main(), it would be separate from the one within the function – “x” could represent two different values within your program, depending on the scope that you are accessing it in. Question 9: In the box below, write a function that returns the minimum value of two passed-in integer variables. The function prototype is given below: int findmin(int val1, int val2); 13 Answer 9: int findmin(int val1, int val2) { int min = val1; if(val2 < val1) { min = val2; } return min; } Question 10: In the box below, show the screen output that would be produced by this program: void testPassByRef(int, int &); task main() { int i=5, j=2; displayTextLine(0, "%d, %d", i, j); testPassByRef(i,j); displayTextLine(2, "%d, %d", i, j); } void teestPassByRef(int x, int &y) { x++; y++; displayTextLine(1, "%d, %d", x, y); } Answer 10: 5, 2 6, 3 5, 3 14 Functions and Arrays In standard C, you can pass a 1-D array to a function like so: int function(int var1[]); However, in RobotC you must create an array type that corresponds to the type and size of array you want to pass, using the keyword typedef, like so: typedef int 1DArray[50]; In this example, it would define an array type for an array with 50 integers. To use this array type, you would declare a function like so: int function(1DArray var1); Notice that in standard C, an array size does not need to be specified, but in RobotC, your type definition must specify a size. In standard C, you can pass a 2-D array to a function like so: int function(int var1[][5]); In RobotC, again, you must again create an array type that corresponds to the type and size of array you want to pass, using the keyword typedef, like so: typedef int 2DArray[5][5]; and use it like so: int function(2DArray var1); Note that in standard C, you can leave the first dimension blank, but you must specify a size for the second dimension. In RobotC, you must specify a size for both dimensions. Keep in mind that arrays (both 1D and 2D) are automatically passed by reference. Functions also cannot return arrays. Question 11: Professors for a new course will be using the following marking scheme: If a student gets 50% or more on final exam If student gets less than 50% on final exam Final exam 50 65 Project 35 20 Quiz 15 15 Final exam marks were recorded out of 100, project marks out of 30 and quiz marks out of 4. Write a function getMarks() that will calculate the final mark of each student. The function has the following parameters: one-dimensional arrays exam, project, quiz, which store the marks for each of the N students, and one-dimensional array finalMark which will store the calculated percentage marks for each of the N students, where N is no more than 10,000. You may assume that N is a symbolic constant that has been defined at the top of the program and that a type definition 15 typedef float Grades1D[10000]; has been given at the top of the program. Your function will also return the number of students whose final mark is less than 50%. Assume that in the main function, the list of grades for exams, projects, and quizzes have been stored in arrays studentExam[N], studentProj[N], studentQuiz[N], and that you will store the final marks in array studentMark[N]. Fill the boxes provided to: A. Show a function call from main() to the getMarks() function. Store the return value of getMarks() into a variable of type int local to main() called numFailures. B. Show the function definition (body) of the getMarks() function, including the function header. Answer 11: A: numFailures = getMarks(studentExam, studentProj, studentQuiz, studentMark); B: int getMarks(Grades1D exam, Grades1D project, Grades1D quiz, Grades1D finalMark) { int failed = 0; int i; for(i = 0; i < N; i++) { if(exam[i] < 50) { finalMark[i] = exam[i]*0.65 + project[i]*0.2 + quiz[i]*0.15; failed++; } else { finalMark[i] = exam[i]*0.5 * project[i]*0.35 + quiz[i]*0.15; } return failed; } } 16 Question 12: You are part of a landmine clearing agency whose job is to remove mines from previous civil wars to make the area safe for civilians. You have a map of the area which is represented as a 2-D array. Each element of the array gives the number of mines in that area for the map. For example, the value 5 at row 4, column 6 means that there are 5 mines in that area that have to be removed. However, a map has been discovered that is also a map of the same minefield. It is suspected that one area has a different number of mines. Your job is to write a program that will compare both maps and find the difference between the maps (if there is a difference). The map array types are declared using the typedef statement typedef int Int2D[255][255]; Your main program will call the following function: int findMapDifference(Int2d map1, Int2d map2, int &row, int &col) If there is an element of one array that differs from the corresponding element of the other array (that is, if the maps are different), then the function returns the value true (that is, 1), and the row and column of the different element are passed back through the parameters &row and &col. If the elements are the same(i.e., the mapsa re the same), then the function returns the value false (i.e., 0), and the row and column parameters are not changed. NOTE: There will be at most one element in the two arrays that are different (that is, there is only one area that is different between the two maps). Complete the main() program and findMapDifference() function on the following page. the main() program must call the function and then report the result by printing to the screen the (row, column) position of the difference if found, otherwise it should report “NO DIFFFERENCE”. 17 Answer 12: A: #define ROWS 255 #define COLS 255 typedef int Int2D[255][255]; int findMapDifference(int2D map1, Int2D map2, int &row, int &col); task main() { int ourMap[255][255]; int foundMap[255][255]; int result, row, col; //Assume the map arrays are filled from a file here fill(ourMap, "map1.txt"); fill(foundMap, "map2.txt"); //Call the funciton and report the results result = findMapDifference(ourMap, foundMap, &row, &col); } if(result == 1) { displayTextLine(0, "Row: %d, Column: %d", row, col); } else { displayTextLine(0, "NO DIFFERENCE"); } B: int findMapDifference(int2D map1, Int2D map2, int &row, int &col) { int i, j; for(i = 0; i < rows; i++) { for(j = 0; j < cols; j++) { if(map1[i][j] != map2[i][j]) { row = i; col = j; return 1; } } } 18 return 0; } Question 13: Professor Smarts takes liquid level measurements of a chemical process. She takes each measurement twice and then performs some analysis on her readings. Help Professor Smarts by writing a function getLevels that has the following parameters: Two arrays of floats, list1 and list2, that store the two lists of measurements An array of floats low that will hold the lower of the two measurements from list1 and list2 an integer n that indicates the size of the arrays An integer low1 that is passed by reference (described below) The function getLevels should work as follows: Compare each element of list1 to the corresponding element of list2 and put the lower value in the array lows in the same index). Count how many times a lower value comes from list1 and store that in low1. Count the number of times that the value at a given index of list1 was within 0.01 of the value of the element at the same index of list2. The function should return this value. Assume that this type definition has been given at the top of the program typedef float Float1D[100]; Assume that in the task main, the list of measurements are stored in arrays levels1[100] and levels2[100], the list of low values will be stored in array lowVals[100], and the number of times a low value comes from levels1 will be stored in a variable called numLow1. Fill out the boxes provided to: A. Show a function call from main() to the getLevel function. Store the returned value of getlevels into a variable of type int local to main() called numClose. B. Write the getLevels function Answer 13: A: int numClose = getLevels(levels1, levels2, lowVals, n, low1) 19 B: int getLevels(Float1D list1, Float1D list2, Float1D lowVals, int n, int &low1) { low1 = 0; int close = 0; for(int i = 0; i < n; i++) { lowVals[i] = list1[i]; if(list2[i] < list1[i]) { lowVals[i] = list2[i]; } if(lowVals[i] == list1[i]) { low1++; } if(abs(list1[i] - list2[i]) < 0.01) { close++; } } } return close; 20 EngLinks APSC 142 Workshop Part 2 (Solutions) 21 Sorting and Searching Although there are many different sorting algorithms in APSC142 we focus on the sequential sort, and the bubble sort. Selection Sort The selection sort finds the smallest element in the array, and swaps it with the first element, so that it will be in the correct location. It then sorts the rest of the array starting at the second element, swapping that with the next smallest element, and so on. Here is one way to implement a selection sort: void selectionSort(Array1D nums, int size) { int i, j, m_index; //outer loop performs N-1 passes for (i = 0; i < size - 1; i++) { // inner loop: scan the unsorted part to find min m_index = i; for (j = i + 1; j < size; j++) { if (nums[j] < nums[m_index]) m_index = j; } if (i != m_index) swap(i, m_index, nums); } } In this example, a swap function would also need to be written. This swap function would simply take the elements in the array at the two indices passed to it, and swap them. 22 Bubble Sort A bubble sort starts at the bottom, and swaps adjacent array elements to place the smaller one, farther up top, and then continues up the array. This repeats from the bottom in subsequent passes until no more swaps are needed. Here is one way to implement a bubble sort: void bubbleSort(Array1D nums, int size) { // outer loop to perform N-1 passes for (i=0; i < size-1; i++) { // keep track of whether a swap occurred swapped = 0; /* inner loop to go from bottom to top while swapping elements */ for (j=size-1; j > i; j--) { if (nums[j] < nums[j-1]) { swap(j, j-1, nums); swapped = 1; } } if (swapped == 0) break; } } Linear Search A linear search searches through an array, in order, until either you find the value you were looking for, or you reach the end of the array. Here is one way to implement a search function: int linSearch(int target, 1DIntArray nums, int N) { for(int i = 0; i < N; i++) { if(nums[i] == target) { return nums[i]; } } return -1; } Binary Search If an array is sorted, a binary search can be used, and is much faster. A binary search checks the middle element of an array first, and compares it to the value we are searching for. If the middle element is larger than the value we are searching for, it will search the lower half of the array. 23 Otherwise, it will search the upper half. This repeats until either the element is found, or we are sure the element is not in the array. Here is one way to implement a binary search: int binarySearch(int target, 1DIntArray nums, int size) { int first = 0, last = size-1, mid; while (first <= last ) { mid = (first + last) / 2; if (target == nums[mid]) return mid; else if ( target < nums[mid]) last = mid - 1; else first = mid + 1; } return -1; } Question 14: The 2-D array stdMarks contains the information of 200 students in a first year course. The first column of the array has the student number, the second column the student mark in the midterm and the third column contains the student mark in the final exam. Write a program that uses a Bubble Sort to sort the rows of the array in descending order according to the student tmark in the final. A small example of the array contents before and after sorting is shown below: Display the contents of the first row after sorting. Write your full program in task main(0 without using any functions. Hint: perform the sort (as in the 1D array case) by looping through the elements of the 3rd column of the array stdMarks, and if the swap condition is satisfied, then use a for loop to swap all the elements of the current row with the previous row. 24 Answer 14: #define ROWS 200 #define COLS 3 task main() { int stdMarks[ROWS][COLS] = {{200, 33, 55}, {201, 26, 28}, {202, 24, 32}, {203, 30, 58}, ...array definition completed}; int length = 200; int temp; for(int i = 0; i < length; i++) { for(int j = length-1; j > i; j--) { if(stdMarks[j][2] < stdMarks[j-1][2]; { for(int k = 0; k < 3; k++) { temp = stdMarks[j][k]; stdMarks[j][k] = stdMarks[j-1][k]; stdMarks[j-1][k] = temp; } } } } } displayTextLine(0, "Student Number: %d", stdMarks[0][0]); displayTextLine(1, "Midterm: %d", stdMarks[0][1]); displayTextLine(2, "Final %d", stdMarks[0][2]); Question 15: Daily maximum temperatures in degrees centigrade for February 2014 in Kingston were recorded, as follows: 1.9, 1.4, -4.1, -5.8, -7.2, -7, -8.3, -7, -8, -7.2, -12.6, -8.4, -4.3, -0.1, -18, -9.2, -11.1, -1.6, -3.7, 2.1, 4.8, 3.8, 0.7, -6.2, -7.4, -8.4, -8.2, -12.6 The values are in order by date from Feb. 1 to Feb. 28. The temperatures are entered in a one-dimensional array, max_temps, in a C program. Complete the program to do the following: A. Calculate the average temperature, avg, in task main, where avg is obtained by summing over all temperature values (Ti, i=0,…,N-1) and dividing by the total number of values (N): 25 𝑁−1 1 𝑎𝑣𝑔 = ∑ 𝑇𝑖 𝑁 𝑖=0 B. Display the average value on the LCD screen C. Find the median temperature value: The median value of an array, is the value in the middle of the sorted array; for example the meian of {3, 5, 6, 9, 12} is 6 and the median of {1.2, 1.8, 3.6, 4.2, 4.9, 6.4} is the average of the two values in the middle: (3.6+4.2)/2 = 3.9. To find the median value of max_temps: copy the array max_temps into a second array sorted_temmps; pass sorted_temps to the function sortArray to sort the temperature values from minimum to maximum (use selection sort or bubble sort) In task main, find the median value from the sorted array; include code to find the median if the number of values, N, in the array is odd or even, where: i. if N is odd, find the middle index of the array and get he value at that position ii. If N is even, find the two middle indices and average the values in those positions D. Display the median temperature on the LCD screen Complete the skeleton code given on the following two pages. 26 Answer 15: #define N 28 typedef float Float1D[31]; //add function prototypes void sortArray(Float1D temps); void swap(int ind_1, int ind_2, Float1D list); task main() { //variable declarations - declare any other variables used in the program float max_temps[] = {1.9, 1.4, -4.1, -5.8, -7.2, -7, -8.3, -7, -8, -7.2, -12.6, -8.4, -4.3, -0.1, -18, -9.2, -11.1,-1.6, -3.7, 2.1, 4.8, 3.8, 0.7, -6.2, -7.4, -8.4, -8.2, -12.6} float sorted_temps[N]; float total = 0; float average; float median; int i, j, middle_element; //calculate and display the average temperature for(i = 0; i < N; i++) { total += max_temps[i]; } average = total/N; displayTextLine(0, "Average: %0.2f", average); //copy the values in max_temps into sorted_temps and call sortArray for(j = 0; j < N; j++) { sorted_temps[j] = max_temps[j]; } sortArray(sorted_temps); // find the median value if N is even or odd and display the median value on the LCD screen if(N%2 == 0) { median = (sorted_temps[N/2] + sorted_temps[(N/2)-1])/2; } else } middle_element = N/2 ; median = sorted_temps[middle_element]; } displayTextLine(1, "Median: %0.2f", median); 27 } /*complete the function sortArray and swap to do a selection or bubble sort*/ void sortArray(Float1D temps) { //declare two loop counters, (i,j) and variable to hold index of min value int i, j, minIndex; //sort array from min to max for(i = 0; i < N-1; i++) { minIndex = i; for(j = i+1; j < N; j++) { if(temps[j] < temps[minIndex]) { minIndex = j; } } //call swap if minIndex!=i (outer loop counter) if(minIndex != i) { swap(i, minIndex, temps); } } } void swap(int ind_1, int ind_2, Float1D list) { int temp = list[ind_1]; list[ind_1] = list[ind_2]; list[ind_2] = temp; } 28 Numerical Methods Monte Carlo Integration Monte Carlo integration is a method of approximating a definite integral. You specify an upper bound on a function y given an interval of x, and create a rectangle within the interval of x from the x-axis to the upper bound on y. You then generate a certain number of random x and y values within this rectangle, and keep track of the number of times the (x,y) point is under the curve of the function y. To approximate the definite integral, you simply multiply the area of the rectangle with the ratio of (x,y) points below the curve, and the total number of (x,y) points generated. Here is one way to implement this numerical method: int N = 1000; int hits = 0; int x_lower = 2; int x_upper = 6; int y_upper = 4; int area_rectangle = (x_upper - x_lower)*(y_upper); for(int i = 0; i < N; i++) { int x = rand() % ((x_upper-x_lower+1) + x_lower); int y = rand() % (y_upper+1); if(y < (-x*x)) { hits++; } } integral = are_rectangle * (hits / N); Keep in mind that this particular implementation will only work for a curve that is purely positive. Numerical Precision Although we count in base 10 (digits from 0 – 9), computers us base 2 (digits from 0-1). This can lead to problems when converting between decimal (base 10), and binary (base 2). For example, when we convert 27.25 to binary, we get 11011.01, and there is no error. However, if we want to represent 27.24 in binary using only 4 bits after the decimal, we get 11011.0011. When you convert that back to decimal, we get 27.1875, leading to an error of 0.0525. This error (called quantization error) can be reduced by using more bits, but there is always a limit to the number of bits we can use to represent numbers, and as a result, there will typically be some error when doing calculations with a computer. Other sources of error include round-off error, overflow/underflow, and truncation error. Gaussian Elimination As we learned in APSC174, we can use Gaussian elimination to solve systems of linear equations. The method involves putting the system of linear equations into an augmented matrix, putting it 29 into row echelon form, and then back-substituting to solve for your unknowns. Here is a way to implement Gaussian elimination for a system of three equations and three unknowns: typedef float 2DFloatArray[3][4]; task main() { int i, n=3; float eqns[3][4] = {{10, -8, 0, 40}, {-8, 20, -6, 0}, {0, -6, 10, -20}}; } forwardElimination(eqns, n); backSubstitution(eqns, n); void forwardElimination(2DFloatArray eqns, int n) { float ratio; } for(int i = 0; i < n; i++) { for(int j = i+1; j M n; j++) { ratio = a[j][i]/a[i][i]; for(k = i; k < n; k++) { a[j][k] -= ratio * a[i][k]; } } } void backSubstitution(2DFloatArray eqns, int n) { for(int i = n-1; i >= 0; i--) { a[i][n] = a[i][n]/a[i][i]; a[i][i] = 1; for(j = i-1; j >= 0; j--) { a[j][n] -= a[j][i] * a[i][n]; a[j][i] = 0; } } } 30 Question 16: Write a program that calculates the Riemann integration of the function 3x2 – 5 from x = 0 to x = 10: Compute the integration as the summation of the rectangles with width 0.5 and height f(xn), where xn is the midpoint of the corresponding rectangle. Display the result on line 4 using 3 decimal points Hint: the grid points are x=0.25, x=0.75, x=1.25, … , x=9.75. Answer 16: task main() { float x, sum = 0; for(x = 0.25, x < 10, x += 0.5) sum = sum + ((3*x*x) - 5) * 0.5; displayTextLine(3, "%0.3f", sum); } Question 17: We have a function f(x) and we want to approximate it using an nth-order polynomial: 𝑓(𝑥) = 𝑓0 + 𝑓1 𝑥 + 𝑓2 𝑥 2 + ⋯ + 𝑓𝑛 𝑥 𝑛 One such approximation is given by the Taylor series expansion: 𝑁 𝑓 (𝑘) (𝑥) 𝑘 𝑓(𝑥) ≈ ∑ 𝑥 𝑘! 𝑘=0 where f(k)(x) is the kth derivative of the function f(x) k! = k*(k-1)*(k-2)*….*3*2*2 For example: 0!=1 1!=1 2!=2*1=2 3!=3*2*1 4!=4*3*2*1 The Taylor series expansion of the cos(x) function is given by: 𝑁 cos(𝑥) ≈ ∑ 𝑘=0 (−1)𝑁 2𝑁 −1𝑘 2𝑘 𝑥2 𝑥4 𝑥 = 1 − + − ⋯+ 𝑥 (2𝑁)! 2𝑘! 2! 4! Problem: RobotC has an internal function called cos(x) to compute the cosine function. Write a program that will compute the value of cos(x) for x=5 using the series provided above. Your program will stop when your approximation is within 0.001 of the real value provided by the internal function. Also, display the value of k at which this condition is satisfied. 31 Answer 17: task main() { int k = 1; float sum = 1; float x = 5; int sign = -1; float exp = 1; float fact = 1; while(abs(sum - cos(x)) > 0.001) { fact = 1; exp = x*x*exp; for(int i = 1; i <= k*2; i++) { fact = fact*i; } sum = sum + exp/fact*sign; sign = -sign; k += 1; } } displayTextLine(2, "%d", k-1); Question 18: The acceleration of a small rocket was measured using an accelerometer. It was found that the acceleration could be modeled using the equation: 𝑎(𝑡) = √𝑡 + 0.05𝑡. When the rocket reached a maximum acceleration of 15m/s2 the acceleration dropped to zero, The acceleration profile is shown below: 32 Complete the code on the following pages to: A. Find the time in seconds at which the rocket reaches maximum acceleration B. Determine the velocity of the rocket at 10 second intervals from t=0s to t=120s, (i.e., velocity at 10s, 20s, …, 120s) and store the values in an array rocketVelocity[n], where n is the number of values to be stored. To find the velocities calculate the definite integral of the acceleration function; use Riemann sum integration with a step size of 1 second. (Note: after the acceleration drops to zero, the rocket is ravelling at constant velocity.) Answer 18: task main() { float accel, time, maxAccelTime; float rocketVelocity[12]; time = 0; //Set initial time to zero accel = 0; //Initialize acceleration value //declare any other variables used in your program int i; float area; // find maxAccelTime = time at which acceleration equals 15 m/s*s maxAccelTime = (-(-2.5) - sqrt(2.5*2.5 - 4*225/400))/(2/400); //display maxAccelTime on LCD screen displayTextLine(0, "Max Accel Time: %0.2f", maxAccelTime); //integrate accel function using Reimann sum to get velocity up to t=120s //store velocity value at each 10 second interval in rocketVelocity[i] area = 0; i = 0; for(i = 1; i <= 12; i++) { area += (sqrt(i*10) + 0.05*i*10)*10; rocketVelocity[i-1] = area; } //display value of final velocity on LCD screen displayTextLine(1, "Final velocity: %0.2f", rocketVelocity[11]); 33 EV3 Robots The following C and RobotC functions should be provided with the exam: motor[] sgn(float x) setMotorSpeed[] sqrt(float x) SensorType[] exp(float x) SensorValue[] wait1Msec(int msecs) SensorEV3_Color sleep(int msecs) SensorEV3_Sound playTone(int freq, byte 10msec_tics) getColorName(int sensor) setPixel(int x, int y) abs(float val) clearPixel(int x, int y) cos(float radians) displayTextline(int line, “ “, …) sin(float radians) eraseDisplay(); Setting a motor speed can be done either using the motor letter (A-D) like so: motor[motorA] = 30; or the motor number (0-3) like so: motor[0] = 30; Using Sensors Below is a list of the most common sensors and their corresponding sensor types: Sensor Sensor Type Ultrasonic (range) sensorEV3_Ulrasonic Sound sensorSoundDBA Colour sensorEV3_Color Touch sensorTouch Sensor types are defined using the port number (S1-S4) like so: SensorType[S1] =sensorTouch ; If using the light sensor to check colours, you will have to specify the sensortype, as well as the sensor mode like so: SensorMode[S1] = modeEV3Color_Color; 34 Screen Pixel Drawing 2D arrays can be used to draw images on the EV3 robot’s’ screen. . The EV3 robot’s screen is 178 rows by 128 columns, and position (0,0) starts in the bottom left corner, with (177,127) in the top right corner. Using the command setPixel(i,j) draws a black pixel as point (i,j) on the screen. Using the command clearPixel(i,j) clears a pixel displayed at that point and returns it back to the typical green. To display an image on the screen, we can use a 2D array of 0s and 1s in the shape of the image we want to display. We can then loop through the array, setting all the 1s, and clearing all the 0s, to draw our image. We can display a simple “+” image in the upper left corner of the EV3 robot’s screen like so: byte pixels[5][5] = {{0,0,1,0,0}, {0,0,1,0,0}, {1,1,1,1,1}, {0,0,1,0,0}, {0,0,1,0,0}}; for(i=0; i < ROWS; i++) { for(j=0; j < COLS; j++) { if(pixels[i][j] == 0) clearPixel(j, 127-i); else if(pixels[i][j] == 1) setPixel(j, 127-i); } } Notice that when setting and clearing pixels, we use “127 – i”, and not just i. This is because in the array, higher indices move lower through the image. However on the screen, higher numbers represent higher pixels. As a result, we use the –i to ensure the image is drawn in the correct orientation. We can change where the image is drawn, by adding offsets. In the example above, the top left of the image corresponds to the top left of the EV3 robot’s screen. However, if we wanted to align the top left of the image closer to the middle of the screen, we could do something like this: byte pixels[5][5] = {{0,0,1,0,0}, {0,0,1,0,0}, {1,1,1,1,1}, {0,0,1,0,0}, {0,0,1,0,0}}; int x_offset = 90; int y_offset = 60; for(i=0; i < ROWS; i++) { for(j=0; j < COLS; j++) { if(pixels[i][j] == 0) clearPixel(x_offset + j, 127 – (y_offset + i)); 35 else if(pixels[i][j] == 1) setPixel(90+ j, 60 - i); } } In this example, the first (top left) pixel will be drawn at (90, 67), and the rest will proceed from there. Question 19: A robot is placed in a hallway of white and black tiles of unequal length. The robot is placed on the first tile which is assumed to be white. The last tile is also white followed by an obstructing wall. Write a robotC program that will make the robot drive down the hallway and stop before or when it hits the wall. Once it reaches the wall, the robot will display the number of black tiles encounter along the way. If you wish to use any sensor, please use the following directions: The ultrasonic sensor is connected to port S2 & the colour sensor is connected to port S3. The touch sensors are connected to port S1 and port S4. The motors are connected to motorA and motorD. Use any combination of sensors that can achieve the task demanded above. 36 Answer 19: #define lightThreshold 40 void Drive(int speed); task main() { //GIVEN DECLARATIONS int lightVal, sonarVal, currentTile = 0, numberOfTiles = 0; SensorType[S2] = sensorEV3_Ultrasonic; SensorType[S3] = sensorEV3_Color; SensorType[S1] = sensorTouch; SensorType[S4] = sensorTouch; while(SensorValue[S1] == 0 && SensorValue[S4] == 0) { lightVal = SensorValue[S3]; if(lightVal < 40 && currentTile > 40) { numberOfTiles++; } currentTile = lightVal; wait1Msec(100); } Drive(0); displayTextLine(0, "%d black tiles", numberOfTiles); } void Drive(int speed) { motor[motorA] = speed; motor[motorD] = speed; } Question 20: A robot is placed inside an arena that is delimited by a black tape. The arena is filled with grey tiles. Program a game that will make the robot stay inside the arena while counting how many times it crossed the grey tiles. The robot will stop if the player claps or whistles. (You are provided with the function void Rotate(int speed, int degrees) that makes the robot rotate with the specified degrees at the speed given.) 37 Specifications: The Light sensor is attached to port S1 The Sound sensor is attached to port S2 The black tape has a reflected light level of 20 The grey tiles have a reflected light level of 40 The white ground has a reflected light level of 60 The clap/whistle level is measured at 65 The motors are on motorA and motorD 38 Answer 20: void Rotate(int speed, int degrees); task main() { //GIVEN DECLARATIONS int lightval, currentTile = 0, numberoftiles = 0; SensorType[S1] = sensorEV3_Color; SensorType[S2] = sensorSoundDBA; motor[motorA] = 20; motor[motorD] = 20; while(SensorValue[S2] < 65) { lightval = sensorValue[S1]; if(lightval == 20) { Rotate(90,20); } else if(lightval == 40 && currentTile != 1) { numberoftiles++; currentTile = 1; displayTextLine(0, "%d", numberoftiles); } if(lightval == 60) { currentTile = 0; } } motor[motorA] = 0; motor[motorD] = 0; }
© Copyright 2024