Archived
1

Add Root Function and Product Function

This commit is contained in:
Kim Wittenburg
2017-08-31 00:04:21 +02:00
parent 43b907ba88
commit 3681e1416c
18 changed files with 864 additions and 0 deletions

8
MathKit/MPFunctionLayout.m Normal file → Executable file
View File

@@ -12,14 +12,18 @@
#import "MPFunction.h"
#import "MPFractionFunction.h"
#import "MPRootFunction.h"
#import "MPParenthesisFunction.h"
#import "MPPowerFunction.h"
#import "MPSumFunction.h"
#import "MPProductFunction.h"
#import "MPFractionFunctionLayout.h"
#import "MPRootFunctionLayout.h"
#import "MPParenthesisFunctionLayout.h"
#import "MPPowerFunctionLayout.h"
#import "MPSumFunctionLayout.h"
#import "MPProductFunctionLayout.h"
#import "NSIndexPath+MPAdditions.h"
@@ -42,6 +46,10 @@
return [[MPPowerFunctionLayout alloc] initWithFunction:function parent:parent];
} else if (class == [MPFractionFunction class]) {
return [[MPFractionFunctionLayout alloc] initWithFunction:function parent:parent];
} else if (class == [MPProductFunction class]) {
return [[MPProductFunctionLayout alloc] initWithFunction:function parent:parent];
} else if (class == [MPRootFunction class]) {
return [[MPRootFunctionLayout alloc] initWithFunction:function parent:parent];
}
return [[self alloc] initWithFunction:function
parent:parent];

8
MathKit/MPFunctionsViewController.m Normal file → Executable file
View File

@@ -10,9 +10,11 @@
#import "MPFunction.h"
#import "MPFractionFunction.h"
#import "MPRootFunction.h"
#import "MPParenthesisFunction.h"
#import "MPPowerFunction.h"
#import "MPSumFunction.h"
#import "MPProductFunction.h"
#import "MPFunctionLayout.h"
@@ -224,16 +226,20 @@ static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMo
- (void)awakeFromNib
{
MPFunction *sumFunction = [[MPSumFunction alloc] init];
MPFunction *productFunction = [[MPProductFunction alloc] init];
MPFunction *parenthesisFunction = [[MPParenthesisFunction alloc] init];
MPFunction *powerFunction = [[MPPowerFunction alloc] init];
MPPowerFunction *squareFunction = [[MPPowerFunction alloc] init];
squareFunction.exponentExpression = [[MPExpression alloc] initWithElement:@"2"];
MPPowerFunction *cubicFunction = [[MPPowerFunction alloc] init];
cubicFunction.exponentExpression = [[MPExpression alloc] initWithElement:@"3"];
MPFunction *rootFunction = [[MPRootFunction alloc] init];
MPFractionFunction *fractionFunction = [[MPFractionFunction alloc] init];
self.functionPrototypes = @[
@{@"function": sumFunction,
@"name": NSLocalizedString(@"Sum", @"Sum Function Name")},
@{@"function": productFunction,
@"name": NSLocalizedString(@"Product", @"Product Function Name")},
@{@"function": parenthesisFunction,
@"name": NSLocalizedString(@"Parenthesis", @"Parenthesis Function Name")},
@{@"function": squareFunction,
@@ -242,6 +248,8 @@ static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMo
@"name": NSLocalizedString(@"Cubic", @"Cubic Function Name")},
@{@"function": powerFunction,
@"name": NSLocalizedString(@"Power", @"Power Function Name")},
@{@"function": rootFunction,
@"name": NSLocalizedString(@"Root", "Root Function Name")},
@{@"function": fractionFunction,
@"name": NSLocalizedString(@"Fraction", @"Fraction Function Name")}
];

70
MathKit/MPProductFunction.h Executable file
View File

@@ -0,0 +1,70 @@
//
// MPProductFunction.h
// MathPad
//
// Created by Kim Wittenburg on 10.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPFunction.h"
/*!
@header
This file contains the <code>MPProductFunction</code> class.
*/
@class MPProductFunction, MPExpression;
/*!
@class MPProductFunction
@abstract This class represents a product function (generally noted using a
capital pi).
@discussion A product function has a start and a target expression indicating
how often the product expression should be evaluated. Both the
value of the start expression and the target expressions are
included in the iterations.
Each iteration the iteration value is incremented by
<code>1</code>. If the start and target expression evaluate to
the same value the product is evaluated once.
*/
@interface MPProductFunction : MPFunction
/*!
@property startExpression
@abstract The value of the first iteration.
@discussion The start expression must define a variable that may be used in
the sum expression. If the start expression does not define a
variable the product function will not be evaluatable.
*/
@property (nonatomic, strong) MPExpression *startExpression; /* Index 0 */
/*!
@property targetExpression
@abstract The value if the last iteration.
@discussion The target expression must not define a variable.
*/
@property (nonatomic, strong) MPExpression *targetExpression; /* Index 1 */
/*!
@property productExpression
@abstract The product expression evaluated multiple times.
@discussion During evaluation of the product expression the variable defined
in the start expression is available. That variable always
contains the value of the current iteration.
The product expression itself must not define a variable.
*/
@property (nonatomic, strong) MPExpression *productExpression; /* Index 2 */
@end

46
MathKit/MPProductFunction.m Executable file
View File

@@ -0,0 +1,46 @@
//
// MPProductFunction.m
// MathPad
//
// Created by Kim Wittenburg on 10.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPProductFunction.h"
#import "MPProductFunctionTerm.h"
#import "MPExpression.h"
@implementation MPProductFunction
MPFunctionAccessorImplementation(StartExpression, _startExpression)
MPFunctionAccessorImplementation(TargetExpression, _targetExpression)
MPFunctionAccessorImplementation(ProductExpression, _productExpression)
- (NSArray *)childrenAccessors
{
return @[@"startExpression", @"targetExpression", @"productExpression"];
}
- (BOOL)expectsVariableDefinitionInChildAtIndex:(NSUInteger)index
{
return index == 0;
}
- (Class)functionTermClass
{
return [MPProductFunctionTerm class];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"Product(From: %@; To: %@; Using: %@)", self.startExpression, self.targetExpression, self.productExpression];
}
@end

View File

@@ -0,0 +1,35 @@
//
// MPProductFunctionLayout.h
// MathPad
//
// Created by Kim Wittenburg on 10.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPFunctionLayout.h"
@class MPProductFunctionLayout, MPProductFunction;
/*!
@class MPProductFunctionLayout
@abstract A product function layout displays a <code>@link
//apple_ref/occ/cl/MPProductFunction@/link</code>.
@discussion A product is drawn using a capital greeg pi (∏) The three
children are placed around it: The start expression below, target
expression above and product expression to the right of it.
*/
@interface MPProductFunctionLayout : MPFunctionLayout
/*!
@method productFunction
@abstract Returns the <code>@link
//apple_ref/occ/cl/MPProductFunction@/link</code> represented by
the receiver.
*/
- (MPProductFunction *)productFunction;
@end

175
MathKit/MPProductFunctionLayout.m Executable file
View File

@@ -0,0 +1,175 @@
//
// MPProductFunctionLayout.m
// MathPad
//
// Created by Kim Wittenburg on 10.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPProductFunctionLayout.h"
#import "MPProductFunction.h"
#import "NSIndexPath+MPAdditions.h"
#define kProductFunctionStartExpressionOffset 0
#define kProductFunctionTargetExpressionOffset 0
#define kProductFunctionProductExpressionOffset 3
#define kProductFunctionTrailingOffset 5
@implementation MPProductFunctionLayout
- (MPProductFunction *)productFunction
{
return (MPProductFunction *)self.function;
}
- (NSUInteger)indexOfLeadingChild
{
return 2;
}
- (NSUInteger)indexOfTrailingChild
{
return 2;
}
- (NSUInteger)indexOfChildAfterChildAtIndex:(NSUInteger)index
{
if (index != 2) {
return 2;
}
return [super indexOfChildAfterChildAtIndex:index];
}
- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index
{
return 0;
}
- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index
{
return 1;
}
- (NSIndexSet *)indexesOfRemainingChildren
{
return [NSIndexSet indexSetWithIndex:2];
}
- (CTLineRef)line
{
CTLineRef line = [self lineForPrivateCacheIndex:0 generator:^CTLineRef{
return [self createLineForString:@"∏"
usingFont:[NSFont fontWithName:@"Times New Roman"
size:self.contextInferredFontSize]];
}];
return line;
}
- (NSRect)localLineBounds
{
NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0);
NSRect startExpressionBounds = [self childLayoutAtIndex:0].bounds;
NSRect targetExpressionBounds = [self childLayoutAtIndex:1].bounds;
CGFloat width = MAX(MAX(startExpressionBounds.size.width, targetExpressionBounds.size.width), lineBounds.size.width);
CGFloat xPosition = (width - lineBounds.size.width) / 2;
return NSMakeRect(xPosition, lineBounds.origin.y, lineBounds.size.width, lineBounds.size.height);
}
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
{
NSRect childBounds = [self childLayoutAtIndex:index].bounds;
NSRect localLineBounds = [self localLineBounds];
NSPoint offset;
if (index == 0) {
// Start Expression
offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2;
offset.y = localLineBounds.origin.y - kProductFunctionStartExpressionOffset - childBounds.size.height - childBounds.origin.y;
} else if (index == 1) {
// Target Expression
offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2;
offset.y = kProductFunctionTargetExpressionOffset + localLineBounds.size.height + localLineBounds.origin.y - childBounds.origin.y;
} else {
// Sum Expression
MPLayout *startExpressionLayout = [self childLayoutAtIndex:0];
MPLayout *targetExpressionLayout = [self childLayoutAtIndex:1];
CGFloat sumWidth = MAX(MAX(localLineBounds.origin.x + localLineBounds.size.width, startExpressionLayout.bounds.size.width), targetExpressionLayout.bounds.size.width);
offset.x = sumWidth + kProductFunctionProductExpressionOffset;
offset.y = 0;
}
return offset;
}
- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index
{
return (index == 0 || index == 1) ? YES : self.usesSmallSize;
}
- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point
{
if (point.x < CTLineGetBoundsWithOptions(self.line, 0).size.width / 2) {
return [NSIndexPath indexPathWithIndex:0];
} else {
return [NSIndexPath indexPathWithIndex:1];
}
}
- (NSRect)generateBounds
{
NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0);
NSRect startExpressionBounds = [self childLayoutAtIndex:0].bounds;
NSRect targetExpressionBounds = [self childLayoutAtIndex:1].bounds;
NSRect sumExpressionBounds = [self childLayoutAtIndex:2].bounds;
NSRect bounds = lineBounds;
bounds.size.width = MAX(lineBounds.size.width, startExpressionBounds.size.width);
bounds.size.height += startExpressionBounds.size.height + kProductFunctionStartExpressionOffset;
bounds.origin.y -= startExpressionBounds.size.height + kProductFunctionStartExpressionOffset;
bounds.size.width = MAX(bounds.size.width, targetExpressionBounds.size.width);
bounds.size.height += targetExpressionBounds.size.height + kProductFunctionTargetExpressionOffset;
bounds.size.width += kProductFunctionProductExpressionOffset + sumExpressionBounds.size.width + kProductFunctionTrailingOffset;
CGFloat yOffsetBottom = bounds.origin.y - sumExpressionBounds.origin.y;
CGFloat yOffsetTop = sumExpressionBounds.size.height - (yOffsetBottom + bounds.size.height);
bounds.size.height = MAX(yOffsetBottom, 0) + bounds.size.height + MAX(yOffsetTop, 0);
bounds.origin.y = MIN(sumExpressionBounds.origin.y, bounds.origin.y);
return bounds;
}
- (void)draw
{
// Get the current context
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
// Set the text matrix
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
// Draw the sum symbol
CTLineRef line = [self line];
CFRetain(line);
NSRect localLineBounds = [self localLineBounds];
CGContextSetTextPosition(context, localLineBounds.origin.x, 0);
CTLineDraw(line, context);
CFRelease(line);
}
@end

37
MathKit/MPProductFunctionTerm.h Executable file
View File

@@ -0,0 +1,37 @@
//
// MPProductFunctionTerm.h
// MathPad
//
// Created by Kim Wittenburg on 10.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPFunctionTerm.h"
/*!
@header
This file contains the <code>MPProductFunctionTerm</code> class.
*/
@class MPProductFunctionTerm;
/*!
@class MPProductFunctionTerm
@abstract Represents and evaluates a <code>@link
//apple_ref/occ/cl/MPProductFunction@/link</code>.
@discussion A product function evaluates its sum term <code>n</code> times.
How often it actually is evaluated depends on the boundary
expressions (start and target). Both are inclusive.
A product function also features a variable that contains the
current value of the iteration. The variable is defined in the
start expression and incremented by <code>1</code> after every
iteration.
*/
@interface MPProductFunctionTerm : MPFunctionTerm
@end

40
MathKit/MPProductFunctionTerm.m Executable file
View File

@@ -0,0 +1,40 @@
//
// MPProductFunctionTerm.m
// MathPad
//
// Created by Kim Wittenburg on 10.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPProductFunctionTerm.h"
#import "MPParsedExpression.h"
@implementation MPProductFunctionTerm
- (NSDecimalNumber *)doEvaluation:(NSError *__autoreleasing *)error
{
MPParsedExpression *startExpression = [self expressionAtIndex:0];
NSDecimalNumber *start = [startExpression evaluate:error];
ReturnNilIfNil(start);
MPEvaluateExpression(target, 1);
MPParsedExpression *sumExpression = [self expressionAtIndex:2];
NSDecimalNumber *value = [NSDecimalNumber one];
for (NSDecimalNumber *current = start;
[current compare:target] <= 0;
current = [current decimalNumberByAdding:[[NSDecimalNumber alloc] initWithInteger:1]]) {
if (![self defineVariable:startExpression.definedVariable value:current error:error]) {
return nil;
}
NSDecimalNumber *currentValue = [sumExpression evaluate:error];
ReturnNilIfNil(currentValue);
value = [value decimalNumberByMultiplyingBy:currentValue];
}
return value;
}
@end

46
MathKit/MPRootFunction.h Executable file
View File

@@ -0,0 +1,46 @@
//
// MPRootFunction.h
// MathPad
//
// Created by Kim Wittenburg on 11.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPFunction.h"
/*!
@header
This file contains the <code>MPRootFunction</code> class.
*/
@class MPRootFunction, MPExpression;
/*!
@class MPRootFunction
@abstract This class represents an arbitrary root function.
@discussion A root has two children: An exponent and the expression to be
rooted.
*/
@interface MPRootFunction : MPFunction
/*!
@property exponentExpression
@abstract The receiver's exponent.
*/
@property (nonatomic, strong) MPExpression *exponentExpression; /* Index 0 */
/*!
@property rootExpression
@abstract The receiver's root expression.
@discussion The root expression is the expression that is to be rooted.
*/
@property (nonatomic, strong) MPExpression *rootExpression; /* Index 1 */
@end

39
MathKit/MPRootFunction.m Executable file
View File

@@ -0,0 +1,39 @@
//
// MPRootFunction.m
// MathPad
//
// Created by Kim Wittenburg on 11.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPRootFunction.h"
#import "MPRootTerm.h"
#import "MPExpression.h"
@implementation MPRootFunction
MPFunctionAccessorImplementation(ExponentExpression, _exponentExpression)
MPFunctionAccessorImplementation(RootExpression, _rootExpression)
- (NSArray *)childrenAccessors
{
return @[@"exponentExpression", @"rootExpression"];
}
- (Class)functionTermClass
{
return [MPRootTerm class];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"Root(%@, %@)", self.exponentExpression, self.rootExpression];
}
@end

42
MathKit/MPRootFunctionLayout.h Executable file
View File

@@ -0,0 +1,42 @@
//
// MPRootFunctionLayout.h
// MathPad
//
// Created by Kim Wittenburg on 11.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPFunctionLayout.h"
/*!
@header
This file contains the <code>MPRootFunctionLayout</code> class.
*/
@class MPRootFunctionLayout, MPRootFunction;
/*!
@class MPRootFunctionLayout
@abstract A root function layout displays a <code>@link
//apple_ref/occ/cl/MPRootFunction@/link</code>.
@discussion A root function is displayed in a very special way. In a way it
can be described as an exponent at the left, a "V" in the middle
and the expression that is to be rooted at the right with a bar
over it.
*/
@interface MPRootFunctionLayout : MPFunctionLayout
/*!
@method rootFunction
@abstract Returns the <code>@link
//apple_ref/occ/cl/MPRootFunction@/link</code> represented by the
receiver.
*/
- (MPRootFunction *)rootFunction;
@end

137
MathKit/MPRootFunctionLayout.m Executable file
View File

@@ -0,0 +1,137 @@
//
// MPRootFunctionLayout.m
// MathPad
//
// Created by Kim Wittenburg on 11.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPRootFunctionLayout.h"
#import "MPRootFunction.h"
#define kRootFunctionTrailingOffset 3
#define kRootFunctionLineWidth 1
#define kRootFunctionLineFragmentLength (self.usesSmallSize ? 3 : 4)
#define kRootFunctionVWidth 5
#define kRootFunctionExpressionXOffset 2
#define kRootFunctionExponentXInset kRootFunctionLineFragmentLength
@implementation MPRootFunctionLayout
- (MPRootFunction *)rootFunction
{
return (MPRootFunction *)self.function;
}
- (NSUInteger)indexOfLeadingChild
{
return 1;
}
- (NSUInteger)indexOfTrailingChild
{
return 1;
}
- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index
{
return 1;
}
- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index
{
return 0;
}
- (NSUInteger)indexOfChildAfterChildAtIndex:(NSUInteger)index
{
return index == 0 ? 1 : NSNotFound;
}
- (NSIndexSet *)indexesOfRemainingChildren
{
return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)];
}
- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index
{
return index == 0;
}
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index
{
NSRect exponentBounds = [self childLayoutAtIndex:0].bounds;
NSRect rootBounds = [self childLayoutAtIndex:1].bounds;
if (index == 0) {
CGFloat x;
if (exponentBounds.size.width > kRootFunctionExponentXInset) {
x = 0;
} else {
x = kRootFunctionExponentXInset - exponentBounds.size.width;
}
return NSMakePoint(x, rootBounds.size.height / 2.0 + rootBounds.origin.y - exponentBounds.origin.y);
} else {
CGFloat rootSymbolXOffset = exponentBounds.size.width > kRootFunctionExponentXInset ? exponentBounds.size.width - kRootFunctionExponentXInset : 0;
CGFloat x = rootSymbolXOffset + kRootFunctionLineFragmentLength + kRootFunctionVWidth + kRootFunctionExpressionXOffset;
return NSMakePoint(x, 0);
}
}
- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point
{
return [[NSIndexPath indexPathWithIndex:1] indexPathByAddingIndex:0];
}
- (NSRect)generateBounds
{
CGFloat x, y, width, height;
NSRect exponentBounds = [self childLayoutAtIndex:0].bounds;
NSRect rootBounds = [self childLayoutAtIndex:1].bounds;
x = 0;
y = rootBounds.origin.y;
CGFloat rootSymbolXOffset = exponentBounds.size.width > kRootFunctionLineFragmentLength ? exponentBounds.size.width : kRootFunctionLineFragmentLength;
width = rootSymbolXOffset + kRootFunctionVWidth + kRootFunctionExpressionXOffset + rootBounds.size.width + kRootFunctionTrailingOffset;
CGFloat heightToExponent = rootBounds.size.height / 2.0 + exponentBounds.size.height;
height = MAX(heightToExponent, rootBounds.size.height + kRootFunctionLineWidth);
return NSMakeRect(x, y, width, height);
}
- (void)draw
{
NSRect exponentBounds = [self childLayoutAtIndex:0].bounds;
NSRect rootBounds = [self childLayoutAtIndex:1].bounds;
CGFloat rootSymbolXOffset = exponentBounds.size.width > kRootFunctionExponentXInset ? exponentBounds.size.width - kRootFunctionExponentXInset : 0;
NSBezierPath *rootPath = [NSBezierPath bezierPath];
NSPoint currentPoint = NSMakePoint(rootSymbolXOffset, rootBounds.size.height / 2.0 + rootBounds.origin.y);
[rootPath moveToPoint:currentPoint];
currentPoint.x += kRootFunctionLineFragmentLength;
[rootPath lineToPoint:currentPoint];
currentPoint.x += kRootFunctionVWidth / 2.0;
currentPoint.y = rootBounds.origin.y;
[rootPath lineToPoint:currentPoint];
currentPoint.x += kRootFunctionVWidth / 2.0;
currentPoint.y = rootBounds.size.height + rootBounds.origin.y;
[rootPath lineToPoint:currentPoint];
currentPoint.x += rootBounds.size.width;
[rootPath lineToPoint:currentPoint];
[rootPath stroke];
}
@end

33
MathKit/MPRootTerm.h Executable file
View File

@@ -0,0 +1,33 @@
//
// MPRootTerm.h
// MathPad
//
// Created by Kim Wittenburg on 11.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPFunctionTerm.h"
/*!
@header
This file contains the <code>MPRootTerm</code> class.
*/
@class MPRootTerm;
/*!
@class MPRootTerm
@abstract Represents a <code>@link
//apple_ref/occ/cl/MPRootFunction@/link</code>.
@discussion A root function is evaluated by evaluating the power
<code>pow(e, 1/n)</code> where <code>e</code> is the expression
to be rooted and <code>n</code> the exponent.
*/
@interface MPRootTerm : MPFunctionTerm
@end

44
MathKit/MPRootTerm.m Executable file
View File

@@ -0,0 +1,44 @@
//
// MPRootTerm.m
// MathPad
//
// Created by Kim Wittenburg on 11.01.15.
// Copyright (c) 2015 Kim Wittenburg. All rights reserved.
//
#import "MPRootTerm.h"
#import "MPParsedExpression.h"
@implementation MPRootTerm
- (NSDecimalNumber *)doEvaluation:(NSError *__autoreleasing *)error
{
MPEvaluateExpression(exponent, 0);
MPEvaluateExpression(root, 1);
if ([root compare:[NSDecimalNumber zero]] < 0) {
// There are no negative roots.
if (error) {
*error = [NSError errorWithDomain:MPMathKitErrorDomain
code:101
userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"The root of a negative number is undefined.", nil)}];
}
return nil;
}
if ([exponent isEqualToNumber:@(0)]) {
// The C pow function returns 1 for pow(0, 0). Mathematically this should be undefined.
if (error) {
*error = [NSError errorWithDomain:MPMathKitErrorDomain
code:101
userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"The 0th root is undefined.", nil)}];
}
return nil;
}
NSDecimalNumber *actualExponent = [[NSDecimalNumber one] decimalNumberByDividingBy:exponent];
return [[NSDecimalNumber alloc] initWithDouble:pow(root.doubleValue, actualExponent.doubleValue)];
}
@end