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
#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
File frac.m
#import <Foundation/Foundation.h>
#import <math.h>
#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
Testing
#import <Foundation/Foundation.h>
#import "frac.h"
#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;
}