我已经阅读了很多关于NSDecimal,NSNumber,NSNumberDecimal,CFNumber ......它开始对我来说是一种丛林。
基本上,我正在尝试创建一个简单的模型类来处理简单的计算,如下所示:
#import <Foundation/Foundation.h>
@interface Test : NSObject
{
float rate;
float amount;
int duration;
}
- (float)capitalizedAmount;
@end
@implementation Test
- (float)capitalizedAmount {
return (amount*pow((1.0+rate),duration));
}
@end
我想以名字作为字符串来访问这些方法和setter,因为我打算有很多其他类这样的类,我只保留一个字段列表来进行键值编码。
// This is just the desired behavior
// This evidently won't work with the previous class definition
Test *obj = [[Test alloc] init];
[NSNumber numberWithInt:10]
...
float r;
r = [obj performSelector:NSSelectorFromString(@"capitalizedAmount")];
我理解这是不可能的,performSelector:
将返回一个对象,因此capitalizedAmount
应该返回一个对象。我已经阅读了关于NSInvocation
的内容以及关于comp.lang的Objective-C Faq中的相关部分。
我也理解我应该使用NSDecimalNumber
,但我想知道两件事:
decimalNumberByAdding:
这样的功能不是太过于挑剔和复杂吗?使用Python,可以很容易地定义__add__
以将运算符与对象一起使用。我应该从NSDecimalNumber
获取浮点值,然后进行计算并返回包含在NSDecimalNumber
中的结果吗?你会如何处理这个问题?我正在寻找一个简单而美观的解决方案!
同一领域的另一个问题是:CFBoolean
是iPhone Core Foundation上BOOL
的对象包装器吗?
非常感谢你的帮助!
答案 0 :(得分:26)
如果您正在处理财务计算,那么您确实应该使用base-10算法来避免标准base-2浮点类型可能出现的舍入错误。所以它是NSDecimal或NSDecimalNumber。由于您正在编写面向对象的代码,因此NSDecimalNumber是您的正确选择。
回答您的问题:只测试您的代码可以揭示您是否可以接受内存开销和性能损失。我并没有真正使用过NSDecimalNumber,但是我敢打赌,Apple的实施非常有效,并且足以满足大多数人的需求。
不幸的是,由于Objective-C不像C ++那样支持运算符重载,因此您将无法避免使用decimalNumberByAdding:
之类的内容。我同意它会使你的代码不那么优雅。
对您发布的代码发表评论:r = [obj performSelector:NSSelectorFromString(@"capitalizedAmount")];
相当不优雅。任
r = [obj performSelector:@selector(capitalizedAmount)];
甚至是简单的
r = [obj capitalizedAmount];
除非您出于某种其他原因需要NSSelectorFromString
语法,否则会更好。
答案 1 :(得分:19)
Ole是正确的,因为在进行财务计算时,您应该使用NSDecimal或NSDecimalNumber来避免浮点数学错误。但是,我的建议是使用NSDecimal及其C函数,而不是NSDecimalNumber。 NSDecimal计算可以更快,因为它们避免创建大量自动释放的对象,在内存使用方面要好得多。
作为一个例子,我在MacBook Air上对这两种类型的数学运算进行了基准测试:
NSDecimal
Additions per second: 3355476.75
Subtractions per second: 3866671.27
Multiplications per second: 3458770.51
Divisions per second: 276242.32
NSDecimalNumber
Additions per second: 676901.32
Subtractions per second: 671474.6
Multiplications per second: 720310.63
Divisions per second: 190249.33
使用NSDecimal与NSDecimalNumber时,除法是唯一没有经历大约五倍性能提升的操作。 iPhone上也有类似的性能改进。这与内存节省一样,是我们最近将Core Plot转换为使用NSDecimal的原因。
您遇到的唯一困难是将值输入和输出NSDecimal类型。直接进出float和integer值可能需要使用NSDecimalNumber作为桥。此外,如果您使用Core Data,您将把值存储为NSDecimalNumbers,而不是NSDecimals。
答案 2 :(得分:3)
我想以名字作为字符串来访问这些方法和setter,因为我打算有很多其他类这样的类,我只保留一个字段列表来进行键值编码。
r = [obj performSelector:NSSelectorFromString(@"capitalizedAmount")];
KVC不仅仅是使用字符串向对象发送消息。请参阅the Key-Value Coding Programming Guide。
我应该从NSDecimalNumber获取浮点值,然后进行计算并返回包含在NSDecimalNumber中的结果吗?
没有。从十进制浮点(float
/ NSDecimalNumber)转换为二进制浮点(double
/ NSDecimal
)是有损的。如果你这样做的话,你的结果对于某些计算是不正确的。