Archived
1
This repository has been archived on 2022-08-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
mathpad/MathPad/MPFunctionValue.m
2014-11-07 19:50:28 +01:00

141 lines
4.5 KiB
Objective-C

//
// MPFunctionValue.m
// MathPad
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPFunctionValue.h"
#import "MPMathRules.h"
double defaultFunction(double value) {return value;};
@implementation MPFunctionValue {
NSDecimalNumber *(^_function)(NSDecimalNumber *);
}
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
{
switch (tokenStream.currentToken.tokenType) {
case MPSinToken:
[tokenStream currentTokenConsumed];
_functionName = @"sin";
return [self initWithTokenStream:tokenStream
function:&sin
takesArcValue:YES
returnsArcValue:NO];
case MPCosToken:
[tokenStream currentTokenConsumed];
_functionName = @"cos";
return [self initWithTokenStream:tokenStream
function:&cos
takesArcValue:YES
returnsArcValue:NO];
case MPTanToken:
[tokenStream currentTokenConsumed];
_functionName = @"tan";
return [self initWithTokenStream:tokenStream
function:&tan
takesArcValue:YES
returnsArcValue:NO];
case MPASinToken:
[tokenStream currentTokenConsumed];
_functionName = @"asin";
return [self initWithTokenStream:tokenStream
function:&asin
takesArcValue:YES
returnsArcValue:NO];
case MPACosToken:
[tokenStream currentTokenConsumed];
_functionName = @"acos";
return [self initWithTokenStream:tokenStream
function:&acos
takesArcValue:YES
returnsArcValue:NO];
case MPATanToken:
[tokenStream currentTokenConsumed];
_functionName = @"atan";
return [self initWithTokenStream:tokenStream
function:&atan
takesArcValue:YES
returnsArcValue:NO];
default:
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:@"Expected Function"
userInfo:nil];
break;
}
return self;
}
- (instancetype)initWithTokenStream:(MPTokenStream *)tokenStream
function:(double (*)(double))function
takesArcValue:(BOOL)takesArc
returnsArcValue:(BOOL)returnsArc
{
self = [self init];
if (self) {
_valueGroup = [[MPValueGroup alloc] initWithTokenStream:tokenStream];
id __weak weakSelf = self;
_function = ^(NSDecimalNumber *value){
if (takesArc) {
value = [weakSelf convertToRadiantsIfNecessary:value];
}
NSDecimalNumber *returnValue = [[NSDecimalNumber alloc] initWithDouble:function(value.doubleValue)];
if (returnsArc) {
returnValue = [weakSelf convertToDegreesIfNecessary:returnValue];
}
return returnValue;
};
}
return self;
}
- (NSDecimalNumber *)convertToRadiantsIfNecessary:(NSDecimalNumber *)degrees
{
if ([MPMathRules sharedRules].isUsingDegrees) {
// * M_PI / 180
return [[degrees decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithInteger:180]];
} else {
return degrees;
}
}
- (NSDecimalNumber *)convertToDegreesIfNecessary:(NSDecimalNumber *)radiants
{
if ([MPMathRules sharedRules].isUsingDegrees) {
// * 180 / M_PI
return [[radiants decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInteger:180]] decimalNumberByDividingBy:[[NSDecimalNumber alloc] initWithDouble:M_PI]];
} else {
return radiants;
}
}
- (BOOL)validate:(NSError *__autoreleasing *)error
{
return [self.valueGroup validate:error];
}
- (NSDecimalNumber *)evaluate
{
return _function([self.valueGroup evaluate]);
}
@end