top of page

FE1008/CY1402-Computing 2016/2017 Semester 2-Question 4

Below are comments and further explanation on question 4.

Question 4.a)

The answers to these questions should be more or less from the notes.

Question 4.a)i)

File I/O operations allow us to read and write to text files.

Question 4.a)ii)

1) It allows us to process large amount of data without having to type it each time

2) There is no need for us to read the data all on the screen as it scrolls by.

Question 4.a)iii)

Using files allows for permanent storage of data from the program on to the hard disk and different programs can access those data on the file that is not yet connected to the current program. However, arrays make use of volatile memory to store the data temporarily only, and does not allow for future use of these data; whether it is by the same program or by other programs. The data is lost once the program exits.

Question 4.a)iv)

EOF stands for end-of-file. It indicates to the program that an end-of-file condition has occurred when reading which means that it has read through until the last character in the file.

Question 4.b)i)

This is easy, write a if-else statement to return the largest number. Just make sure you get the syntax right and that the function has a return type of double (only floating point variables can represent real numbers; float is OK, but normally we use double) and takes in 2 double variables:

double func1(double a, double b)

{

if(a > b)

return a;

else

return b;

}

*Note: this variable a and b are local to this function func1 only and is not accessible outside func1.

Question 4.b)ii)

This question is VERY IMPORTANT. I would say that this is probably the hardest question in the whole paper. It took me quite a while to get it right after trying a lot of different coding methods. I shall go through some of them which, I think, you could have made the same mistake as me and identify the errors within the incorrect code. Below are my thought process, codes and mistakes.

Try 1:

My first thought was to use fabs() and if the difference was less than 0.009, it means that they would share the same value up to 2 d.p. How I came up with 0.009 was that I thought about the difference between the maximum and minimum value for which 2 numbers will still have the same value up to 2 d.p. and that is e.g. 1.239 (max) and 1.230 (min). Why the need for fabs() is because we would not know which value would be bigger and since we are taking difference between 2 floating point numbers, fabs() would be more suitable.

double func2(double a, double b) // you can use 'int' return type too

{

if(fabs(a - b) <= 0.009)

return 1; // the question says to return a non-zero number,

I've chosen 1 to be my non-zero value.

else

return 0; // This statement can also be written outside the

else statement (without the else clause).

}

However, there is major flaw with this code. Think of the example when func2 takes in1.234 and 1.225 instead. The if statement turns out to be true! (1.234 -1.225 = 0.009) and returns a non-zero. Since 1.234 and 1.225 do not share the same the value up to 2 d.p., evidently, there is a huge loop-hole with this code logic.

Try 2:

How about multiplying the numbers by 100, so that the first 2 decimal places takes up the tens' and ones' placing, while 3rd decimal place becomes the 1st decimal place (1.234 becomes 123.4). We follow up with using floor() to remove the remaining decimal places. This would in theory leave us with integer numbers and we can just compare if they are the same by looking at the absolute difference between these 2 integers, use of abs() not fabs() since we are dealing with integers.

int func2(double a, double b) // you can use double return type too

{

int c, d;

c = floor(a * 100);

d = floor(b * 100);

if(abs(c - d) < 1)

return 1;

else

return 0;

}

Few things to note before I go into the problem with this piece of code:

1) It is possible to use either double or integer return type since the question did not have a specific value we should return.

2) It is also possible to assign the "floor-ed" value back to a and b respectively without having to assign them to new integer variables. i.e.

a = floor(a * 100);

b = floor(b * 100);

But do take note that since we are using floating point, you should use fabs() instead of abs().

3) Alternatively, the if statement can be written as:

if(abs(c-d) == 0) or if(!abs(c-d)) or if(c == d)

! operator will change any non-zero value(True) to zero(False) and zeros(False) to 1 (True).

4) The return 0; statement in the else statement, in this case can be taken out of the else clause and be written as (they work the same):

int func2(double a, double b) // you can use double return type too

{

int c, d;

c = floor(a * 100);

d = floor(b * 100);

if(abs(c - d) < 1)

return 1;

return 0;

}

5) I did not put any curly brackets {} for the if statement. This means that only the statement immediately after the if condition will be seen by the compiler as part of the if clause; the second statement onwards will not be seen as part of the if clause. If you wish to put 2 or more statements in a if/else clause, use the curly brackets {}. For more information on if-else statements, click here.

Now to the problem with this piece of code: due to floating point precision errors, floor(a * 100) or floor(b * 100) may not return the value as we expect it to. If we were to enter 1.16, floor(1.16 * 100) returns 115 rather than 116. This issue with floating point precision error is very complex and I have limited knowledge in this area so if you are interested, you can ask your tutor for more information or search online using "floating point precision errors" as the keywords.

This piece of code is actually good enough, just that it has some precision errors that will give us the wrong results occasionally. I decided to move one step further to reduce such errors.

Try 3:

Since multiplying by 100 had precision errors in the ones' place, how about multiplying it by a 1000?

After trying out various numbers, my conclusion is that when we floor a floating point number (float, double, long double), the general trend is that when we multiply this number by a factor of 10, 100, or 1000, ... ..., the precision errors only affects the digit in the ones' place. However, I do expect this error to affect more digits such as the tens' and hundreds' place when the multiplication gives a large number.

Nevertheless, this is still a breakthrough. At least for now, we can be sure that the thousands', hundreds', tens' place are very likely to be representing the correct value. We now move on to the problem of comparing the values of the 2 numbers. We cannot use the absolute difference between the 2 numbers to determine if they are the same at the tens' place as explained in Try 1. We need an alternative method to check, I thought of using checking thousands', hundreds' and tens' placing individually and if they are all equal, the 2 numbers in theory will have the same value up to 2 d.p.

int func2(double a, double b)

{

int c = floor(a*1000);

int d = floor(b*1000);

int c_thousands = c - c%1000; // Line 6

int d_thousands = d - d%1000;

c = c % 1000; // Line 8

d = d % 1000;

int c_hundreds= c - c%100;

int d_hundreds = d - d%100;

c = c % 100;

d = d % 100;

int c_tens = c - c%10;

int d_tens = d - d%10;

if((c_thousands == d_thousands) // Line 19

&&(c_hundreds == d_hundreds)

&&(c_tens == d_tens))

return 1;

return 0;

}

How Line 6 works is that first we shall find the remainder of c when divided by 1000. This will give us a remainder without thousands' place and above, leaving the hundreds', tens' and ones' places. Then we shall deduct this remainder from the original value to get the thousands' digit (even if the number was 11 000, we will get 11 for the thousands' place).

After we have stored the value of the thousands' place, we check the remainder for its hundreds' and tens' place respectively. To make things simpler, I reassigned the remainder value to c and d in Line 8. The process of figuring out the hundreds' and tens' place continues.

After we have sorted out the thousands', hundreds' and tens' places of both numbers (a & b), we need to compare each of them to know for sure that all of them are the same to conclude that they have the same value up to 2 d.p. The if condition in Line 19 states that if the thousands' place of c is EQUAL to the thousands' place of d AND if the hundreds' place of c is EQUAL to the hundreds' place of d AND if the tens' place of c is EQUAL to the tens' place in d, we are sure that this number is the same up to 2 d.p., return a non-zero value of 1. If any of the digits do not match each other, the if statement turns out to be false and moves on the other code below the if statement, which is return zero (which could also be written as part of the else clause).

Try 4:

Let me try to simplify this code. The code from Try 2 looks simple enough but we need to combine with Try 3's logic.

int func2(double a, double b)

{

int c = floor(a*1000);

int d = floor(b*1000);

c /= 10; // integer division drops the decimals

d /= 10;

if(abs(c - d) == 0)

return 1;

else

return 0;

}

A few more pointers to that note: firstly, this program is still not perfect. Double variables can take in really large values and its range of values far exceeds the range integer variable can hold. While it is not too much of a problem if the values of a and b are does not exceed integer's range of values but this means that overflow is still a potential problem with this piece of code.

If you think you have a better way of doing this, please share it with me, either in the forum or email.

*Just a side note: I noticed another solution from the PYP answers

int func2(double a, double b)

{

if(fabs(a - b) < 0.01) // number is same up to 2 d.p.

return 1; // the question says to return a non-zero number,

I've chosen 1 to be my non-zero value.

else

return 0; // This statement can also be written outside the

else statement (without the else clause).

}

This code makes use of the absolute difference between the 2 numbers to determine if they are actually same up to 2d.p. even though it should work for some numbers, it might not be able to differentiate (e.g.) 1.231000 with 1.231000 + 0.009999 = 1.240999. Thus, this code is also flawed since it will return true for numbers that are not the same up to 2 d.p. In general, it not advisable to make use of the absolute difference of the 2 numbers when you are comparing whether 2 numbers have the same values up to a certain number of d.p. or to compare if numbers are same up to tens place or hundreds place.

Question 4.b)iii)

After a whole chunk of code from part b)ii), it's time to put things together. There isn't much difficulty to this question just make sure you include the appropriate header files and write the function declaration/prototype. I've included the func1 and func2 definitions which are not required by the question.

#include <stdio.h>

#include <math.h> // for floor()

// Function declaration/prototype

double func1(double a, double b);

double func2(double a, double b);

int main(void)

{

double a, b;

printf("Enter a real number: ");

scanf("%lf", &a);

printf("Enter another real number: ");

scanf("%lf", &b);

if(!func2(a, b)) // ! swap true to false, false to true

printf("The largest number is %.5f", func1(a, b));

return 0;

}

double func1(double a, double b)

{ if(a > b)

return a;

else

return b;

}

double func2(double a, double b)

{

int c = floor(a*1000);

int d = floor(b*1000);

c /= 10;

d /= 10;

if(c == d)

return 1; // if same up to 2 d.p. return 1, seen as true

else

return 0; // if not, return 0, seen as false

}

This is one version of my source code, if you want to see other variations, please check out FE1008/CY1402-Computing 2016/2017 Semester 2-Comments & Source Code.

That's all for Question 4. If you have any doubts, opinions or suggestions, feel free to leave them in forum section or email me @ KYX@outlook.sg. Thanks~

Related Posts

See All
Recent Posts

Related Posts

Leave your comments or questions below:

bottom of page