Arithmetic/Rational/Objective-C

From Rosetta Code
Arithmetic/Rational/Objective-C is part of Rational Arithmetic. You may find other members of Rational Arithmetic at Category:Rational Arithmetic.
File frac.h

<lang objc>#import <Foundation/Foundation.h>

@interface RCRationalNumber : NSObject {

@private
 int numerator;
 int denominator;
 BOOL autoSimplify;
 BOOL withSign;

} +(instancetype)valueWithNumerator:(int)num andDenominator: (int)den; +(instancetype)valueWithDouble: (double)fnum; +(instancetype)valueWithInteger: (int)inum; +(instancetype)valueWithRational: (RCRationalNumber *)rnum; -(instancetype)initWithNumerator: (int)num andDenominator: (int)den; -(instancetype)initWithDouble: (double)fnum precision: (int)prec; -(instancetype)initWithInteger: (int)inum; -(instancetype)initWithRational: (RCRationalNumber *)rnum; -(NSComparisonResult)compare: (RCRationalNumber *)rnum; -(id)simplify: (BOOL)act; -(void)setAutoSimplify: (BOOL)v; -(void)setWithSign: (BOOL)v; -(BOOL)autoSimplify; -(BOOL)withSign; -(NSString *)description; // ops -(id)multiply: (RCRationalNumber *)rnum; -(id)divide: (RCRationalNumber *)rnum; -(id)add: (RCRationalNumber *)rnum; -(id)sub: (RCRationalNumber *)rnum; -(id)abs; -(id)neg; -(id)mod: (RCRationalNumber *)rnum; -(int)sign; -(BOOL)isNegative; -(id)reciprocal; // getter -(int)numerator; -(int)denominator; //setter -(void)setNumerator: (int)num; -(void)setDenominator: (int)num; // defraction -(double)number; -(int)integer; @end</lang>

File frac.m

<lang objc>#import <Foundation/Foundation.h>

  1. import <math.h>
  2. import "frac.h"

// gcd: Greatest common divisor#Recursive_Euclid_algorithm // if built in as "private" function, add static.

static int lcm(int a, int b) {

 return a / gcd(a,b) * b;

}

@implementation RCRationalNumber // initializers -(instancetype)init {

 NSLog(@"initialized to unity");
 return [self initWithInteger: 1];

}

-(instancetype)initWithNumerator: (int)num andDenominator: (int)den {

 if ((self = [super init]) != nil) {
   if (den == 0) {
     NSLog(@"denominator is zero");
     return nil;
   }
   [self setNumerator: num];
   [self setDenominator: den];
   [self setWithSign: YES];
   [self setAutoSimplify: YES];
   [self simplify: YES];
 }
 return self;

}

-(instancetype)initWithInteger:(int)inum {

 return [self initWithNumerator: inum andDenominator: 1];

}

-(instancetype)initWithDouble: (double)fnum precision: (int)prec {

 if ( prec > 9 ) prec = 9;
 double p = pow(10.0, (double)prec);
 int nd = (int)(fnum * p);
 return [self initWithNumerator: nd andDenominator: (int)p ];

}

-(instancetype)initWithRational: (RCRationalNumber *)rnum {

 return [self initWithNumerator: [rnum numerator] andDenominator: [rnum denominator]];

}

// comparing -(NSComparisonResult)compare: (RCRationalNumber *)rnum {

 if ( [self number] > [rnum number] ) return NSOrderedDescending;
 if ( [self number] < [rnum number] ) return NSOrderedAscending;
 return NSOrderedSame;

}

// string rapresentation of the Q -(NSString *)description {

 [self simplify: [self autoSimplify]];
 return [NSString stringWithFormat: @"%@%d/%d", [self isNegative] ? @"-" : 

( [self withSign] ? @"+" : @"" ), abs([self numerator]), [self denominator]]; }

// setter options -(void)setAutoSimplify: (BOOL)v {

 autoSimplify = v;
 [self simplify: v];

} -(void)setWithSign: (BOOL)v {

 withSign = v;

}

// getter for options -(BOOL)autoSimplify {

 return autoSimplify;

}

-(BOOL)withSign {

 return withSign;

}

// "simplify" the fraction ... -(id)simplify: (BOOL)act {

 if ( act ) {
   int common = gcd([self numerator], [self denominator]);
   [self setNumerator: [self numerator]/common];
   [self setDenominator: [self denominator]/common];
 }
 return self;

}

// diadic operators -(id)multiply: (RCRationalNumber *)rnum {

 int newnum = [self numerator] * [rnum numerator];
 int newden = [self denominator] * [rnum denominator];
 return [RCRationalNumber valueWithNumerator: newnum

andDenominator: newden]; }

-(id)divide: (RCRationalNumber *)rnum {

 return [self multiply: [rnum reciprocal]];

}

-(id)add: (RCRationalNumber *)rnum {

 int common = lcm([self denominator], [rnum denominator]);
 int resnum = common / [self denominator] * [self numerator] +
   common / [rnum denominator] * [rnum numerator];
 return [RCRationalNumber valueWithNumerator: resnum andDenominator: common];

}

-(id)sub: (RCRationalNumber *)rnum {

 return [self add: [rnum neg]];

}

-(id)mod: (RCRationalNumber *)rnum {

 return [[self divide: rnum] 

sub: [RCRationalNumber valueWithInteger: [[self divide: rnum] integer]]]; }

// unary operators -(id)neg {

 return [RCRationalNumber valueWithNumerator: -1*[self numerator]

andDenominator: [self denominator]]; }

-(id)abs {

 return [RCRationalNumber valueWithNumerator: abs([self numerator])

andDenominator: [self denominator]]; }

-(id)reciprocal {

 return [RCRationalNumber valueWithNumerator: [self denominator]

andDenominator: [self numerator]]; }

// get the sign -(int)sign {

 return ([self numerator] < 0) ? -1 : 1;

}

// or just test if negative -(BOOL)isNegative {

 return [self numerator] < 0;

}

// Q as real floating point -(double)number {

 return (double)[self numerator] / (double)[self denominator];

}

// Q as (truncated) integer -(int)integer {

 return [self numerator] / [self denominator];

}

// set num and den indipendently, fixing sign accordingly -(void)setNumerator: (int)num {

 numerator = num;

}

-(void)setDenominator: (int)num {

 if ( num < 0 ) numerator = -numerator;
 denominator = abs(num);

}

// getter -(int)numerator {

 return numerator;

}

-(int)denominator {

 return denominator;

}

// class method +(instancetype)valueWithNumerator:(int)num andDenominator: (int)den {

 return [[self alloc] initWithNumerator: num andDenominator: den];

}

+(instancetype)valueWithDouble: (double)fnum {

 return [[self alloc] initWithDouble: fnum];

}

+(instancetype)valueWithInteger: (int)inum {

 return [[self alloc] initWithInteger: inum];

}

+(instancetype)valueWithRational: (RCRationalNumber *)rnum {

 return [[self alloc] initWithRational: rnum];

} @end</lang>

Testing

<lang objc>#import <Foundation/Foundation.h>

  1. import "frac.h"
  2. import <math.h>

int main() {

 @autoreleasepool {
   int i;
   for(i=2; i < 0x80000; i++) {
     int candidate = i;
     RCRationalNumber *sum = [RCRationalNumber valueWithNumerator: 1
			                            andDenominator: candidate];
     int factor;
     for(factor=2; factor < sqrt((double)candidate); factor++) {
       if ( (candidate % factor) == 0 ) {
	  sum = [[sum add: [RCRationalNumber valueWithNumerator: 1

andDenominator: factor]] add: [RCRationalNumber valueWithNumerator: 1 andDenominator: (candidate/factor)]];

       }
     }
     if ( [sum denominator] == 1 ) {
       printf("Sum of recipr. factors of %d = %d exactly %s\n",

candidate, [sum integer], ([sum integer]==1) ? "perfect!" : "");

     }
   }
 }
 return 0;

}</lang>