简体   繁体   English

Coredata和NSDecimalNumber

[英]Coredata and NSDecimalNumber

I'm having issue with decimal numbers stored in core data. 我在核心数据中存储的十进制数字有问题。 When I'm saving number 0.6789 into database it is saved as 0.6788999999999999. 当我将数字0.6789保存到数据库中时,它将另存为0.6788999999999999。

I have read somewhere that it is recommended to have decimal number columns as decimal to maintain the precision as core data automatically handles NSDecimalNumber for decimal columns in core data. 我在某处读过,建议将十进制数列作为十进制数以保持精度,因为核心数据会自动处理核心数据中十进制列的NSDecimalNumber。

Below is my entity class: 下面是我的实体类:

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

@implementation TestEntity
@dynamic cost;
@end

This is how I'm inserting data: 这就是我插入数据的方式:

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

Please someone help me on, how should I handle the decimal numbers and their precision when inserted into database? 请有人帮我,插入数据库后如何处理十进制数字及其精度?

Core Data is backed by SQLite. 核心数据由SQLite支持。 According to the SQLite documentation SQLite only supports integers up to 64 bit and floating point numbers with the 64bit IEEE 754 format ( double in Objective C). 根据SQLite文档, SQLite仅支持64位 IEEE 754格式(Objective C中为double )的最大64位整数和浮点数。 So the precision is limited to these types, which is about 18.75 significant digits for integers and 15.75 digits for floating point numbers. 因此,精度仅限于这些类型,整数的有效位数约为18.75,浮点数的有效位数约为15.75。

Usually a double or int64_t are right for most of the applications except for those where precision beyond 15-18 significant digits is required. 通常,对于大多数应用程序来说, doubleint64_t是正确的,但要求精度超过15-18个有效数字的应用程序除外。 In some jurisdictions, banking institutions have to store decimal numbers with high precision by law and they use special types for this. 在某些辖区中,银行机构必须根据法律高精度地存储小数,并且为此使用特殊类型。

If your application is standard I would use int64_t or double . 如果您的应用程序是标准的,我将使用int64_tdouble If you use NSDecimalNumber it is going to be stored as a 64-bit type by the SQLite engine (floating point or integer depending on the existence of a fractional part). 如果使用NSDecimalNumber它将由SQLite引擎存储为64位类型(浮点数或整数取决于小数部分的存在)。 This means your precision will be limited to 15-18 digits. 这意味着您的精度将限制为15到18位数字。

If you want to use NSDecimalNumber because of its high precision arithmetic, you still will be limited to 15/18-digits but rounding errors will not be introduced if your dynamic range can be expressed as a 15/18-digit number (with fractional part or without). 如果由于NSDecimalNumber的高精度算法而要使用它,则仍将其限制为NSDecimalNumber位数字,但是如果动态范围可以表示为15/18位数字(带小数部分),则不会引入舍入误差。或没有)。

If your dynamic range is greater, NSDecimalNumber provides 38 digits. 如果您的动态范围更大,则NSDecimalNumber提供38位数字。 In order to store it in a Core Data SQLite-backed persistent storage and be able to maintain the 38 digits, you should convert it to string, back and forth, so that it gets stored in Core Data as a string. 为了将其存储在由Coreite支持SQLite的持久性存储中并能够保持38位数字,您应该将其来回转换为字符串,以便将其作为字符串存储在Core Data中。 You could create a category on your subclass of NSManagedObject with a couple of methods to store (encode) and retrieve (decode) the number to a string. 您可以在NSManagedObject的子类上创建一个类别,该类别具有几种方法来存储(编码)和检索(解码)数字为字符串。 The underlying property in your model should the be a string, instead of a number. 模型中的基础属性应该是字符串,而不是数字。

NSDecimalNumber has two methods -stringValue and -initWithString: to do the conversion for you. NSDecimalNumber有两种方法-stringValue-stringValue -initWithString:为您执行转换。 You just need to construct two methods that rely on these in your custom category. 您只需要构造两个在自定义类别中依赖它们的方法。

In summary: 综上所述:

  • If you need decimal numbers, use double for 15 significant digits 如果需要十进制数字,请为15个有效数字使用double
  • If you don't need decimal numbers, use int64_t for 18 significant digits 如果不需要十进制数字,请使用int64_t表示18个有效数字
  • If you need decimal numbers with high precision accuracy, use NSDecimalNumber for 38 significant digits (with the conversion to string for storage in CoreData) 如果您需要高精度的十进制数字,请使用NSDecimalNumber表示38个有效数字(转换为字符串以存储在CoreData中)

SQLite which is backend for CoreData has no support for decimals and float is used instead. 作为CoreData后端的SQLite不支持小数,而是使用float。


From SQLite documentation: 从SQLite文档中:

Each column in an SQLite 3 database is assigned one of the following type affinities: TEXT NUMERIC INTEGER REAL BLOB 向SQLite 3数据库中的每一列分配以下类型关联性之一:TEXT NUMERIC INTEGER REAL BLOB

More details are at SQLite documentation https://sqlite.org/datatype3.html 3.1.1. 有关更多详细信息,请参见SQLite文档https://sqlite.org/datatype3.html 3.1.1。 Affinity Name Examples. 相似性名称示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM