Coredata和NSDecimalNumber

时间:2015-06-02 01:03:58

标签: objective-c core-data nsdecimalnumber

我遇到存储在核心数据中的十进制数问题。当我将数字0.6789保存到数据库时,它保存为0.6788999999999999。

我在某处读过,建议将十进制数列作为十进制来保持精度,因为核心数据会自动处理核心数据中十进制列的NSDecimalNumber。

以下是我的实体类:

@interface TestEntity : NSManagedObject
@property (nonatomic, retain) NSDecimalNumber * cost;
@end

@implementation TestEntity
@dynamic cost;
@end

这就是我插入数据的方式:

TestEntity *envelope = [NSEntityDescription insertNewObjectForEntityForName:@"TestEntity" inManagedObjectContext:self.managedObjectContext];
envelope.cost = [NSDecimalNumber decimalNumberWithString:@"0.6789"];
[self.managedObjectContext save:nil];

请有人帮助我,如何在插入数据库时​​处理十进制数及其精度?

2 个答案:

答案 0 :(得分:3)

核心数据由SQLite支持。根据{{​​3}},SQLite仅支持最大SQLite documentation的整数和64 bit格式的浮点数(目标C中的double)。因此精度仅限于这些类型,整数约为18.75个有效数字,浮点数约为15.75个数字。

通常doubleint64_t适用于大多数应用程序,但需要超过15-18位有效数字的应用程序除外。在某些司法管辖区,银行机构必须依法存储高精度的十进制数字,并为此使用特殊类型。

如果您的申请是标准的,我会使用int64_tdouble。如果使用NSDecimalNumber,它将由SQLite引擎存储为64位类型(浮点或整数,取决于是否存在小数部分)。这意味着您的精确度将限制在15-18位。

如果由于其高精度算术而要使用NSDecimalNumber,则仍然会限制为15/18位数,但如果64bit IEEE 754可以表示为a,则不会引入舍入误差15/18位数字(小数部分或无分数)。

如果您的动态范围较大,NSDecimalNumber会提供38位数字。为了将其存储在Core Data SQLite支持的持久存储中并且能够维护38位数,您应该将其转换为字符串,来回,以便它作为字符串存储在Core Data中。您可以在NSManagedObject的子类上创建一个类别,使用几种方法来存储(编码)并将数字检索(解码)为字符串。模型中的基础属性应该是字符串,而不是数字。

NSDecimalNumber有两种方法-stringValue-initWithString:为您进行转化。您只需构建两个依赖于自定义类别的方法。

总结:

  • 如果您需要小数,请使用double获取15位有效数字
  • 如果您不需要十进制数字,请使用int64_t获取18位有效数字
  • 如果您需要具有高精度准确度的十进制数字,请使用NSDecimalNumber获取38位有效数字(转换为字符串以便存储在CoreData中)

答案 1 :(得分:1)

作为CoreData后端的SQLite不支持小数,而是使用float。

来自SQLite文档:

  

SQLite 3数据库中的每个列都分配了以下之一   类型亲和力:TEXT NUMERIC INTEGER REAL BLOB

更多细节见SQLite文档https://sqlite.org/datatype3.html 3.1.1。亲和力名称示例。