// // MPFunctionValue.m // MathPad // // Created by Kim Wittenburg on 11.10.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPElementaryFunctionTerm.h" #import "MPParsedExpression.h" #import "MPPowerFunction.h" #import "MPProductTerm.h" #import "MPToken.h" #import "MPExpression.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"]) { func = &asin; returnsArc = YES; } else if ([function isEqualToString:@"acos"]) { func = &acos; returnsArc = YES; } else if ([function isEqualToString:@"atan"]) { func = &atan; returnsArc = YES; } else { NSAssert(true, @"function must be one of (sin, cos, tan, asin, acos, atan)."); } [self setFunction:func takesArcValue:takesArc returnsArcValue:returnsArc]; _term = term; } 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; } return _function(value); } @end