Monday 11 May 2009

Chapter 7 - More on Classes

Comment

So far I'm liking the whole 'Synthesized Accessor Methods'. It is a process included since Objective-C 2.0 was implemented and basically allows you to have your 'setter' and 'getter' methods - a.k.a 'accessor methods' - automatically generated. Using this synthesized method is supposed to produce methods that are efficient regardless of the platform the program is eventually ran on.


@d. As you mentioned earlier, the dot operator is mentioned. I believe you told me its origins lie originally with C++

If I end up using interchanging notation between the two in the following examples, I'm just trying to get a feel for which one I prefer. The 'dot operator' way certainly looks cleaner when performing the same operation on two objects together.


For example:


-(void) addNumerators: (fraction *) f

{

numerator = numerator + f.numerator;

}


as opposed to:


{

numerator = numerator + [f numerator];

}


Examples

1. Add the following methods to the Fraction class to round out the arithmetic operations on fractions. Reduce the result within the method in each case:


//Subtract argument from receiver

-(Fraction *) subtract: (Fraction *) f;

//Multiply receiver by argument

-(Fraction *) multiply: (Fraction *) f;

//Divide receiver by argument

-(Fraction *) divide: (Fraction *) f;


ANS - Copy and Paste of implemented methods


-(Fraction *) subtract: (Fraction *) f

{

// To subtract two fractions:

// a/b - c/d = ((a*d) - (b*c)) / (b * d)

// result will store the result of the subtration

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

int resultNum, resultDenom;

resultNum = numerator * f.denominator - denominator * f.numerator;

resultDenom = denominator * f.denominator;

[result setNumerator: resultNum andDenominator: resultDenom];

[result reduce];

return result;

}


-(Fraction *) multiply: (Fraction *) f

{

// To multiply two fractions:

// a/b * c/d

//result will store the result of the multiplication

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

int resultNum, resultDenom

resultNum = numerator * f.numerator;

resultDenom = denominator * f.denominator;

[result setNumerator: resultNum andDenominator: resultDenom];

[result reduce];

return result;

}


-(Fraction *) divide: (Fraction *) f

{

// To divide two fractions:

// a/b * d/c

//result will store the result of the multiplication

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

int resultNum, resultDenom;

resultNum = numerator * f.denominator;

resultDenom = denominator * f.numerator;

[result setNumerator: resultNum andDenominator: resultDenom];

[result reduce];

return result;

}


Although not necessarily required, I produced a program to demonstrate these methods in use. Below are the copy and paste of the code and the console output:


#import

#import "Fraction.h"


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

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


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

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

Fraction *resultFraction;

[aFraction setNumerator: 3 andDenominator: 4];

[bFraction setNumerator: 1 andDenominator: 2];

NSLog (@"Function | Expected Output |");

NSLog (@"Actual Output | |");

NSLog (@"---------------------------------");

resultFraction = [aFraction subtract: bFraction];

NSLog (@"subtract: | 1/4 |");

[resultFraction print];

resultFraction = [aFraction multiply: bFraction];

NSLog (@"multiply: | 3/8 |");

[resultFraction print];

resultFraction = [aFraction divide: bFraction];

NSLog (@"divide: | 3/2 |");

[resultFraction print];


[resultFraction release];

[pool drain];

return 0;

}


[Session started at 2009-05-11 03:41:07 +0100.]

Function | Expected Output |

Actual Output | |

---------------------------------

subtract: | 1/4 |

1/4

multiply: | 3/8 |

3/8

divide: | 3/2 |

3/2


The Debugger has exited with status 0.


2. Modify the print method from your Fraction class so that it takes an optional BOOL argument that indicates whether the fraction should be reduced for display. If it is to be reduced, be sure you don't make any permanent changes to the fraction itself.


ANS - Copy and Paste of implemented code and console output


-(void) print

{

BOOL reduce;

int temp, n, d;

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

n = numerator;

d = denominator;

temp = n % d;

if ( temp != 0 ) {

reduce = TRUE;

[r setNumerator: n andDenominator: d];

}

if ( reduce = TRUE ) {

[r reduce];

NSLog (@"This fraction was reduced to: %i/%i", r.numerator, r.denominator);

}

else {

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

}

}


#import

#import "Fraction.h"


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

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


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

[aFraction setNumerator: 6 andDenominator: 8];

NSLog (@"Actual value of aFraction: %i/%i", aFraction.numerator, aFraction.denominator);

[aFraction print];

[pool drain];

return 0;

}


The Debugger Debugger is attaching to process

[Session started at 2009-05-15 20:48:42 +0100.]

2009-05-15 20:48:42.197 FractionTest[633:10b] Actual value of aFraction: 6/8

2009-05-15 20:48:42.198 FractionTest[633:10b] This fraction was reduced to: 3/4


The Debugger has exited with status 0.


3. Modify Program 7.7 to also display the resulting sum as a fraction, not just as a real number.


ANS - Copy and Paste of the new code and console output of fraction


#import

#import "Fraction.h"


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

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


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

Fraction *sum = [[Fraction alloc] init], *sum2;

int i, n, pow2;

[sum setNumerator: 0 andDenominator: 1]; //Set 1st fraction to 0

NSLog (@"Enter your value for n:");

scanf ("%i", &n);

pow2 = 2;

for ( i = 1; i <= n; ++i ) {

[aFraction setNumerator: 1 andDenominator: pow2];

sum2 = [sum add: aFraction];

[sum release]; //release previous sum

sum = sum2;

pow2 *= 2;

}

NSLog (@"After %i iterations, the sum is %g", n, [sum convertToNum]);

NSLog (@"num/denom: %g/%g", [sum numerator], [sum denominator]);

[aFraction release];

[sum release];

[pool drain];

return 0;

}



[Session started at 2009-05-15 21:37:38 +0100.]

2009-05-15 21:37:38.738 FractionTest[992:10b] Enter your value for n:

5

2009-05-15 21:37:40.522 FractionTest[992:10b] After 5 iterations, the sum is 0.96875

2009-05-15 21:37:40.522 FractionTest[992:10b] num/denom: 6.95336e-310/5.29949e-315


The Debugger has exited with status 0.


4. Will your Fraction class work with negative fractions? For example, can you add -1/4 and -1/2 and get the correct result? When you think you have the answer, write a test program to try it.


ANS - I believe the outcome will be it can based on the merits we discussed earlier. With the addition algorithm the sign is never lost or changed and thus the calculation is completed successfully. This is similar to the subtract algorithm in that the two negatives - (-1/2) become 1/2. For multiplication the sign is lost, however this makes mathematical sense as two negatives result in a positive. This is also the case with division.


#import

#import "Fraction.h"


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

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


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

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

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

[aFraction setNumerator: -1 andDenominator: 4];

[bFraction setNumerator: -1 andDenominator: 2];

[result setNumerator: 0 andDenominator: 0];

result = [aFraction add: bFraction];

NSLog (@"-1/4 + -1/2 = ");

[result print];


[aFraction release];

[bFraction release];

[result release];

[pool drain];

return 0;

}


[Session started at 2009-05-15 21:10:08 +0100.]

2009-05-15 21:10:08.321 FractionTest[761:10b] -1/4 + -1/2 =

2009-05-15 21:10:08.322 FractionTest[761:10b] This fraction was reduced to: -3/4


The Debugger has exited with status 0.


5. Modify the Fraction's print method to display fractions greater than 1 as mixed numbers. For example, the fraction 5/3 should be displayed as 1 2/3.


ANS - Copy and Paste of new print method and console output illustrating different testing data.


-(void) print

{

BOOL reduce;

int temp, n, d, whole;

float result;

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

n = numerator;

d = denominator;

[r setNumerator: n andDenominator: d];

temp = n % d;

if ( temp != 0 ) {

reduce = TRUE;

}

if ( n / d > 0 ) {

whole = n / d;

r.numerator -= r.denominator * whole;

if ( reduce = TRUE ) {

[r reduce];

}

result = (float) r.numerator / r.denominator;

if ( result != 0 ) {

NSLog (@"This fraction was simplified to: %i and %i/%i", whole, r.numerator, r.denominator);

}

else {

NSLog (@"This fraction was simplified to: %i", whole);

}

}

else {

if ( reduce = TRUE ) {

[r reduce];

}

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

}

[r release];

}


[Session started at 2009-05-17 12:23:19 +0100.]

2009-05-17 12:23:19.464 FractionTest[790:10b] Num: 5 Denom: 3

2009-05-17 12:23:19.465 FractionTest[790:10b] This fraction was simplified to: 1 and 2/3


The Debugger has exited with status 0.

[Session started at 2009-05-17 12:23:34 +0100.]

2009-05-17 12:23:34.361 FractionTest[805:10b] Num: 6 Denom: 2

2009-05-17 12:23:34.363 FractionTest[805:10b] This fraction was simplified to: 3


The Debugger has exited with status 0.

[Session started at 2009-05-17 12:23:47 +0100.]

2009-05-17 12:23:47.118 FractionTest[820:10b] Num: 12 Denom: 8

2009-05-17 12:23:47.120 FractionTest[820:10b] This fraction was simplified to: 1 and 1/2


The Debugger has exited with status 0.


6. Exercise 7 in Chapter 4, "Data Types and Expressions," defined a new class called Complex for working with complex imaginary numbers. Add a new method called add: that can be used to add two complex numbers. To add two complex numbers you simply add the real parts and the imaginary parts , as shown here:

(5.3 + 7i) + (2.7 + 4i) = 8 + 11i

Have the add: method store and return the result as a new Complex number, based on the following method declaration:

-(Complex *) add: (Complex *) ;

Make sure you address any potential memory leakage issues in your test program.


7. Given the Complex class developed in exercise 7 of Chapter 4 and the extension made in exercise 6 of this chapter, create separate Complex.h and Complex.m interface and implementation files. Create a separate test program file to test everything.


ANS - Copy and Paste of both exercise 6 and 7 and its console output. (it's a long one)


//

// Complex.h

// ComplexNum

//

// Created by Waqas Arshid on 17/05/2009.

// Copyright 2009 __MyCompanyName__. All rights reserved.

//


#import



@interface Complex : NSObject

{

int real;

int imaginary;

}


-(void) setReal: (double) a andImaginary: (double) b;

-(void) print; // display as a + bi

-(double) real;

-(double) imaginary;

-(Complex *) add: (Complex *) c;


@end


//

// Complex.m

// ComplexNum

//

// Created by Waqas Arshid on 17/05/2009.

// Copyright 2009 __MyCompanyName__. All rights reserved.

//


#import "Complex.h"



@implementation Complex


-(void) setReal: (double) a andImaginary: (double) b

{

real = a;

imaginary = b;

}


-(void) print

{

NSLog(@"Complex number equals: %d + %di", real, imaginary);

}


-(double) real

{

return real;

}


-(double) imaginary

{

return imaginary;

}


- (Complex *) add: (Complex *) c

{

Complex *result = [[Complex alloc] init];

double r, i;

r = real + c.real;

i = imaginary + c.imaginary;

[result setReal: r andImaginary: i];

return result;

}


@end


#import

#import "Complex.h"

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

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

Complex *aComp = [[Complex alloc] init];

Complex *bComp = [[Complex alloc] init];

Complex *resultComp;

[aComp setReal: 5.3 andImaginary: 7];

[bComp setReal: 2.7 andImaginary: 11];

resultComp = [aComp add: bComp];

[resultComp print];


[aComp release];

[bComp release];

[resultComp release];

[pool drain];

return 0;

}


[Session started at 2009-05-17 16:33:06 +0100.]

2009-05-17 16:33:06.608 ComplexNum[2100:10b] Complex number equals: 7 + 18i


The Debugger has exited with status 0.