Monday 27 April 2009

Chapter 6 - Making Decisions

Comment


EDIT: Have updated this post with my answers to questions 5, 6, 7. Question 6 was particularly interesting and I feel my approach hasn't necessarily covered all bases. Maybe we could discuss other alternatives to solving it.


P.S. - For the harder ones I've added comments for you to see why I chose a certain approach, I hope they help ;)


At this point the book starts to list good programming practices to develop which is key in maintaining consistency and maintainability in your own code. Maybe a good way of putting it is through an analogy. If your sloppy and careless when writing by hand, when you go back to review what you have just written, it's completely illegible and all your work is wasted. When programming, your laziness may not lead to such drastic consequences but the result is still wasting time deciphering the code. So it's good to develop good coding practices in the first place.


The idea of 'nonzero' and zero was also interesting to read in how the idea of expressions relates to computer systems and computer-based languages.


I didn't really comprehend the section on 'conditional operators' in the sense of where you would use it when you can just use 'if' and 'switch' statements. The book relates this to 'Preprocessors' in a later chapter though.


Exercises

1. Write a program that asks the user to type in two integer values. Test these two numbers to determine whether the first is evenly divisible by the second and then display an appropriate message at the terminal.


ANS - Copy and Paste of code and console output of two possible outcomes


#import


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

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


int aValue, anotherValue, test;

NSLog (@"Enter first value:");

scanf ("%i", &aValue);

NSLog (@"Enter second value:");

scanf ("%i", &anotherValue);

test = aValue % anotherValue;

if ( test == 0 )

NSLog (@"Success! First number is divisible by second.");

else

NSLog (@"Sorry. First number undivisible by second.");

[pool drain];

return 0;

}


[Session started at 2009-04-27 18:23:07 +0100.]

2009-04-27 18:23:07.384 Chap6[277:10b] Enter first value:

50

2009-04-27 18:23:09.783 Chap6[277:10b] Enter second value:

10

2009-04-27 18:23:11.007 Chap6[277:10b] Success! First number is divisible by second.


The Debugger has exited with status 0.

[Session started at 2009-04-27 18:23:14 +0100.]

2009-04-27 18:23:14.732 Chap6[278:10b] Enter first value:

50

2009-04-27 18:23:17.447 Chap6[278:10b] Enter second value:

11

2009-04-27 18:23:18.135 Chap6[278:10b] Sorry. First number undivisible by second.


The Debugger has exited with status 0.



2. Program 6.8A displays the value in the accumulator even if an invalid operator is entered or division by zero is attempted. Fix that problem.


ANS - I was trying to get this to work by having a nested for loop within a switch which doesn't seem to play well. Will bring the project in.


#import


@interface Calculator: NSObject

{

double accumulator;

double memory;

}


-(void) setAccumulator: (double) value;

-(void) clear;

-(double) accumulator;


-(void) add: (double) value;

-(void) subtract: (double) value;

-(void) multiply: (double) value;

-(void) divide: (double) value;


-(double) changeSign; // change sign of accumulator

-(double) reciprocal; // 1/accumulator

-(double) xSquared; // accumulator squared


-(double) memoryClear; // clear memory

-(double) memoryStore; // set memory to accumulator

-(double) memoryRecall; // set accumulator to memory

-(double) memoryAdd; // add accumulator to memory

-(double) memorySubtract; // subtract accumulator from memory


@end


@implementation Calculator


-(void) setAccumulator: (double) value;

{

accumulator = value;

}


-(void) clear;

{

accumulator = 0;

}


-(double) accumulator;

{

return accumulator;

}


-(void) add: (double) value;

{

accumulator += value;

return NSLog(@"The resulting value of accumulator is: %f", accumulator);

}


-(void) subtract: (double) value;

{

accumulator -= value;

return NSLog(@"The resulting value of accumulator is: %f", accumulator);

}


-(void) multiply: (double) value;

{

accumulator *= value;

return NSLog(@"The resulting value of accumulator is: %f", accumulator);

}


-(void) divide: (double) value;

{

accumulator /= value;

return accumulator;

}


-(double) changeSign;

{

return -accumulator;

}


-(double) reciprocal;

{

return 1 / accumulator;

}


-(double) xSquared;

{

return accumulator * accumulator;

}


@end


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

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


double value1, value2;

char operator;

Calculator *deskCalc = [[Calculator alloc] init];

NSLog (@"Type in your expression.");

scanf ("%lf %c %lf", &value1, &operator, &value2);

[deskCalc setAccumulator: value1];

switch ( operator )

{

case '+':

[deskCalc add: value2];

NSLog (@"%.2f", [deskCalc accumulator]);

break;

case '-':

[deskCalc subtract: value2];

NSLog (@"%.2f", [deskCalc accumulator]);

break;

case '*':

case 'x':

[deskCalc multiply: value2];

NSLog (@"%.2f", [deskCalc accumulator]);

break;

case '/':

if ( value2 != 0 )

[deskCalc divide: value2];

NSLog (@"%.2f", [deskCalc accumulator]);

else //build error: syntax error before 'else'

NSLog (@"Division by zero.");

//If I reverse the condition to 'value2 == 0' no errors occur but all instructions are executed regardless of placement

break;

default:

NSLog (@"Unknown operator.");

break;

}

[pool drain];

return 0;

}



3. Modify the print method from the Fraction class so that whole numbers are displayed as such (so the fraction 5/1 should display as simply 5). Also modify the method to display fractions with a numerator of 0 as simply zero.


ANS - I don't think this task was quite clear enough however I interpreted it to mean to go back and alter a Program 6.2 in the book so that when two integers are entered and the second is '1' then a whole value should be returned rather than 'n / 1'.


The program does all it is required to do apart from returning the value '0.0' when dividing by zero. I am unsure why this is the case.


#import


@interface Fraction: NSObject

{

int numerator;

int denominator;

}


-(void) print;

-(void) setNumerator: (int) n;

-(void) setDenominator: (int) d;

-(int) numerator;

-(int) denominator;

-(double) convertToNum;


@end



@implementation Fraction

-(void) print

{

if ( numerator == 0 )

NSLog (@"zero");

else if ( denominator == 1 )

NSLog (@" %i ", numerator);

else

NSLog (@" %i/%i ", numerator, denominator);

}


-(void) setNumerator: (int) n

{

numerator = n;

}


-(void) setDenominator: (int) d

{

denominator = d;

}


-(int) numerator

{

return numerator;

}


-(int) denominator

{

return denominator;

}


-(double) convertToNum

{

if ( denominator != 0 )

return (double) numerator / denominator;

else

return 0.0;

}


@end



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

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


int aValue1, aValue2, bValue1, bValue2;

Fraction *aFraction = [[Fraction alloc] init];

Fraction *bFraction = [[Fraction alloc] init];

NSLog (@"Enter values for numerator/denominator for - aFraction:");

scanf ("%i, %i", &aValue1, &aValue2);

NSLog (@"Enter values for numerator/denominator for - bFraction:");

scanf ("%i, %i", &bValue1, &bValue2);

[aFraction setNumerator: aValue1];

[aFraction setDenominator: aValue2];

[bFraction setNumerator: bValue1];

[bFraction setDenominator: bValue2];

[aFraction print];

NSLog (@"=");

NSLog (@"%g", [aFraction convertToNum]);

[bFraction print];

NSLog (@"=");

NSLog (@"%g", [bFraction convertToNum]);

[aFraction release];

[bFraction release];

[pool drain];

return 0;

}


The Debugger Debugger is attaching to process

[Session started at 2009-04-27 22:48:51 +0100.]

2009-04-27 22:48:51.662 Ex3[280:10b] Enter values for numerator/denominator for - aFraction:

5, 1

2009-04-27 22:48:56.634 Ex3[280:10b] Enter values for numerator/denominator for - bFraction:

5, 0

2009-04-27 22:49:03.218 Ex3[280:10b] 5

2009-04-27 22:49:03.218 Ex3[280:10b] =

2009-04-27 22:49:03.219 Ex3[280:10b] 5

2009-04-27 22:49:03.219 Ex3[280:10b] 5/0

2009-04-27 22:49:03.219 Ex3[280:10b] =

2009-04-27 22:49:03.220 Ex3[280:10b] 0


The Debugger has exited with status 0.



4. Write a program that acts as a simple printing calculator. The program should allow the user to type in expressions of the following form:

number operator

The program should recognize the following operators:

+ - * / S E


The S operator tells the program to set the accumulator to the typed-in number, and the E operator tells the program that execution is to end. The arithmetic operations are performed on the contents of the accumulator, with the number that was keyed in acting as the second operand.


Make sure the program detects divisions by 0 and also checks for unknown operators. Use the calculator class developed in Program 6.8 for performing your calculations.


ANS - I made a mess of this one


#import


//Implement a Calculator class


@interface Calculator: NSObject

{

double accumulator;

}


//accumulator methods

-(void) setAccumulator: (double) value;

-(void) clear;

-(double) accumulator;


//arithmetic methods

-(void) add: (double) value;

-(void) subtract: (double) value;

-(void) multiply: (double) value;

-(void) divide: (double) value;


@end


@implementation Calculator


-(void) setAccumulator: (double) value

{

accumulator = value;

}

-(void) clear

{

accumulator = 0;

}

-(double) accumulator

{

return accumulator;

}

-(void) add: (double) value

{

accumulator += value;

}

-(void) subtract: (double) value

{

accumulator -= value;

}

-(void) multiply: (double) value

{

accumulator *= value;

}

-(void) divide: (double) value

{

accumulator /= value;

}


@end



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

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


double aValue;

char operator;

Calculator *simpleCalc = [[Calculator alloc] init];

NSLog (@"Begin Calculations");

scanf ("%lf %c", &aValue, &operator);

do

switch ( operator )

{

case 'S':

[simpleCalc setAccumulator: aValue];

NSLog (@"= %lf", [simpleCalc accumulator]);

break;

case '+':

[simpleCalc add: aValue];

NSLog (@"= %lf", [simpleCalc accumulator]);

break;

case '-':

[simpleCalc subtract: aValue];

NSLog (@"= %lf", [simpleCalc accumulator]);

break;

case '*':

[simpleCalc multiply: aValue];

NSLog (@"= %lf", [simpleCalc accumulator]);

break;

case '/':

if ( aValue == 0 )

NSLog (@"Division by zero. Try again.");

else

[simpleCalc divide: aValue];

NSLog (@"= %lf", [simpleCalc accumulator]);

break;

case 'E':

NSLog (@"= %lf", [simpleCalc accumulator]);

NSLog (@"End of Calculations.");

break;

default:

NSLog (@"Unknown operator.");

break;

}

while ( operator != 'E' );

[pool drain];

return 0;

}


5. We developed Program 5.9 to reverse the digits of an integer typed in from the terminal. However, this program does not function well if you type in a negative number. Find out what happens in such a case, and then modify the program so that negative numbers are correctly handled. By this, we mean that if the number -8645 were typed in, for example, the output of the program should be 5468-.


ANS - Copy and Paste of the code and its console output. I incorporated your 'flagging' method into this program, thanks for the tip.


#import


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

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


int number, right_digit;

BOOL flag;

flag = NO;

NSLog (@"Enter your number");

scanf ("%i", &number);

if ( number < 0 ) {

flag = YES;

number = -number;

NSLog (@"Number: %i", number);

}

do {

right_digit = number % 10;

NSLog (@"%i", right_digit);

number /= 10;

}

while ( number != 0 );

if ( flag == YES) {

NSLog (@"-");

}

[pool drain];

return 0;

}


[Session started at 2009-05-01 19:21:31 +0100.]

2009-05-01 19:21:31.850 Ex5[843:10b] Enter your number

-55

2009-05-01 19:21:35.324 Ex5[843:10b] Number: 55

2009-05-01 19:21:35.324 Ex5[843:10b] 5

2009-05-01 19:21:35.325 Ex5[843:10b] 5

2009-05-01 19:21:35.325 Ex5[843:10b] -


The Debugger has exited with status 0.

[Session started at 2009-05-01 19:21:39 +0100.]

2009-05-01 19:21:39.382 Ex5[844:10b] Enter your number

55

2009-05-01 19:21:40.772 Ex5[844:10b] 5

2009-05-01 19:21:40.772 Ex5[844:10b] 5


The Debugger has exited with status 0.


6. Write a program that takes an integer keyed in from the terminal and extracts and displays each digit of the integer in English. So if the user types in 932, the program should display the following:

nine

three

two

(Remember to display zero if the user just types 0.) Note: This exercise is a hard one!


ANS - Copy and Paste of code and console output. Note: for values ending in zero I was unable to present them as required. e.g. 700 would become 'seven' and not 'seven zero zero'


#import


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

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


int integer = 0, digit = 0, reversed = 0;

NSLog (@"Enter integer to be converted into English");

scanf ("%i", &integer);

if ( integer < 0 ) {

integer = -integer;

NSLog (@"negative");

}

while ( integer != 0 ) {

reversed += integer % 10; //adds the extracted digit at the end of the integer to be the first digit of the reversed integer

//NSLog (@"value: %i", reversed);

integer /= 10; //divides the integer ready to extract the next digit

if ( integer /= 10 != 0 ) { //only if all digits are not extracted is the reversed multiplied

reversed *= 10; //multiplies the reversed integer ready for the next digit

}

}

do {

digit = reversed % 10;

switch ( digit ) {

case 0:

NSLog (@"zero");

break;

case 1:

NSLog (@"one");

break;

case 2:

NSLog (@"two");

break;

case 3:

NSLog (@"three");

break;

case 4:

NSLog (@"four");

break;

case 5:

NSLog (@"five");

break;

case 6:

NSLog (@"six");

break;

case 7:

NSLog (@"seven");

break;

case 8:

NSLog (@"eight");

break;

case 9:

NSLog (@"nine");

break;

default:

NSLog (@"invalid digit");

break;

}

reversed /= 10; //divides the reversed integer ready for the next digit to be extracted, prevents an endless loop

}

while ( reversed != 0 );

[pool drain];

return 0;

}


[Session started at 2009-05-05 01:31:16 +0100.]

2009-05-05 01:31:16.113 Ex6[636:10b] Enter integer to be converted into English

786

2009-05-05 01:31:18.352 Ex6[636:10b] seven

2009-05-05 01:31:18.353 Ex6[636:10b] eight

2009-05-05 01:31:18.353 Ex6[636:10b] six


The Debugger has exited with status 0.

[Session started at 2009-05-05 01:31:21 +0100.]

2009-05-05 01:31:21.159 Ex6[637:10b] Enter integer to be converted into English

-786

2009-05-05 01:31:23.080 Ex6[637:10b] negative

2009-05-05 01:31:23.080 Ex6[637:10b] seven

2009-05-05 01:31:23.081 Ex6[637:10b] eight

2009-05-05 01:31:23.081 Ex6[637:10b] six


The Debugger has exited with status 0.

[Session started at 2009-05-05 01:31:25 +0100.]

2009-05-05 01:31:25.695 Ex6[638:10b] Enter integer to be converted into English

0

2009-05-05 01:31:28.449 Ex6[638:10b] zero


The Debugger has exited with status 0.


7. Program 6.10 has several inefficiencies. One inefficiency results from checking even numbers. Because any even number greater than 2 obviously cannot be prime, the program could simply skip all even numbers as possible primes and as possible divisors. The inner for loop is also inefficient because the value of p is always divided by all values of d from 2 through p-1. You can avoid this inefficiency if you add a test for the value of isPrime in the condition of the for loop. In this manner, you can set up the for loop to continue as long as no divisor is found and the value of d is less than p. Modify the Program 6.10 to incorporate these two changes; then run the program to verify its operation.


ANS - Copy and Paste of code with comments and console output


//generates a table of prime numbers from the range 2 through 50


#import


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

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


int p, d;

BOOL isPrime;

for ( p = 2; p <= 50; ++p ) {

isPrime = YES;

if ( p % 2 == 0 && p != 2 ) { //All even values aside from 2 are not prime

continue;

}

for ( d = 2; d < isprime ="="">YES; ++d ) { //As soon as the number is found not to be prime the remaining checks are not required

if ( d % 2 == 0 ) { //An odd number is not evenly divisible by an even

continue; //one and since no even numbers remain, this test is unnecessary

}

if ( p % d == 0 ) {

isPrime = NO;

}

}

if ( isPrime == YES ) {

NSLog (@"%i ", p);

}

}

[pool drain];

return 0;

}


[Session started at 2009-05-05 00:47:18 +0100.]

2009-05-05 00:47:18.871 Ex7[337:10b] 2

2009-05-05 00:47:18.872 Ex7[337:10b] 3

2009-05-05 00:47:18.873 Ex7[337:10b] 5

2009-05-05 00:47:18.873 Ex7[337:10b] 7

2009-05-05 00:47:18.873 Ex7[337:10b] 11

2009-05-05 00:47:18.874 Ex7[337:10b] 13

2009-05-05 00:47:18.874 Ex7[337:10b] 17

2009-05-05 00:47:18.874 Ex7[337:10b] 19

2009-05-05 00:47:18.874 Ex7[337:10b] 23

2009-05-05 00:47:18.875 Ex7[337:10b] 29

2009-05-05 00:47:18.875 Ex7[337:10b] 31

2009-05-05 00:47:18.875 Ex7[337:10b] 37

2009-05-05 00:47:18.876 Ex7[337:10b] 41

2009-05-05 00:47:18.876 Ex7[337:10b] 43

2009-05-05 00:47:18.876 Ex7[337:10b] 47


The Debugger has exited with status 0.