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/MathKit/MPElementaryFunctionTerm.m
2015-01-04 22:16:27 +01:00

125 lines
4.1 KiB
Objective-C

//
// MPElementaryFunctionTerm.m
// MathKit
//
// Created by Kim Wittenburg on 11.10.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPElementaryFunctionTerm.h"
#import "MPParsedExpression.h"
#import "MPMathRules.h"
@implementation MPElementaryFunctionTerm {
NSDecimalNumber *(^_function)(NSDecimalNumber *);
}
- (instancetype)initWithFunctionIdentifier:(NSString *)function
term:(MPTerm *)term
{
self = [super init];
if (self) {
NSAssert(function != nil, @"function must not be nil.");
NSAssert(term != nil, @"term must not be nil.");
double (*func)(double);
BOOL takesArc = NO;
BOOL returnsArc = NO;
if ([function isEqualToString:@"sin"]) {
func = &sin;
takesArc = YES;
} else if ([function isEqualToString:@"cos"]) {
func = &cos;
takesArc = YES;
} else if ([function isEqualToString:@"tan"]) {
func = &tan;
takesArc = YES;
} else if ([function isEqualToString:@"asin"] || [function isEqualToString:@"arcsin"]) {
func = &asin;
returnsArc = YES;
} else if ([function isEqualToString:@"acos"] || [function isEqualToString:@"arccos"]) {
func = &acos;
returnsArc = YES;
} else if ([function isEqualToString:@"atan"] || [function isEqualToString:@"arctan"]) {
func = &atan;
returnsArc = YES;
} else if ([function isEqualToString:@"lg"] || [function isEqualToString:@"log"]) {
func = &log10;
} else if ([function isEqualToString:@"ln"]) {
func = &log;
} else {
NSAssert(true, @"function must be one of (sin, cos, tan, asin, arcsin, acos, arccos, atan, arctan, lg, log, ln).");
}
[self setFunction:func
takesArcValue:takesArc
returnsArcValue:returnsArc];
_term = term;
_functionIdentifier = function.copy;
}
return self;
}
- (void)setFunction:(double (*)(double))function
takesArcValue:(BOOL)takesArc
returnsArcValue:(BOOL)returnsArc
{
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;
};
}
- (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;
}
}
- (NSDecimalNumber *)doEvaluation:(NSError *__autoreleasing *)error
{
NSDecimalNumber *value = [self.term evaluate:error];
if (!value) {
return nil;
}
NSDecimalNumber *result = _function(value);
if ([result isEqualToNumber:[NSDecimalNumber notANumber]]) {
result = nil;
if (error) {
NSString *errorDescription = [NSString stringWithFormat:NSLocalizedString(@"%@ is not defined for the value %@.", nil), self.functionIdentifier, [value descriptionWithLocale:[NSLocale currentLocale]]];
*error = [NSError errorWithDomain:MPMathKitErrorDomain
code:102
userInfo:@{NSLocalizedDescriptionKey: errorDescription}];
}
}
return result;
}
@end