Corrected Deformed Number Format Added "arcsin", "arccos", "arctan", "lg", "log", "ln" Elementary Functions
113 lines
3.5 KiB
Objective-C
113 lines
3.5 KiB
Objective-C
//
|
|
// 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"] || [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, acos, atan, lg, log, ln).");
|
|
}
|
|
[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
|