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.
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.
Below is my entity class:
@interface TestEntity : NSManagedObject
@property (nonatomic, retain) NSDecimalNumber * cost;
TestEntity *envelope = [NSEntityDescription insertNewObjectForEntityForName:@"TestEntity" inManagedObjectContext:self.managedObjectContext];
envelope.cost = [NSDecimalNumber decimalNumberWithString:@"0.6789"];
Core Data is backed by 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). 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.
int64_t are right for most of the applications except for those where precision beyond 15-18 significant digits is required. 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
double. 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). This means your precision will be limited to 15-18 digits.
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).
If your dynamic range is greater,
NSDecimalNumber provides 38 digits. 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. 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. The underlying property in your model should the be a string, instead of a number.
NSDecimalNumber has two methods
-initWithString: to do the conversion for you. You just need to construct two methods that rely on these in your custom category.
doublefor 15 significant digits
int64_tfor 18 significant digits
NSDecimalNumberfor 38 significant digits (with the conversion to string for storage in CoreData)