8

I'm trying to store Latitude/Longitudes in core data. These end up being anywhere from 6-20 digit precision.

And for whatever reason, i had them as floats in Core Data, its rounding them and not giving me the exact values back. I tried "decimal" type, with no luck either.

Are NSStrings my only other option?

EDIT

NSManagedObject:

@interface Event :  NSManagedObject  
{
}

@property (nonatomic, retain) NSDecimalNumber * dec;
@property (nonatomic, retain) NSDate * timeStamp;
@property (nonatomic, retain) NSNumber * flo;
@property (nonatomic, retain) NSNumber * doub;

Here's the code for a sample number that I store into core data:

NSNumber *n = [NSDecimalNumber decimalNumberWithString:@"-97.12345678901234567890123456789"];

The above value printed. Sweet, value I expected:

Printing description of n:

-97.12345678901234567890123456789

Code to access it again:

NSNumber *n = [managedObject valueForKey:@"dec"];
NSNumber *f = [managedObject valueForKey:@"flo"];
NSNumber *d = [managedObject valueForKey:@"doub"];

Printed values:

Printing description of n:
    -97.1234567890124

    Printing description of f:
    <CFNumber 0x603f250 [0xfef3e0]>{value = -97.12345678901235146441, type = kCFNumberFloat64Type}

    Printing description of d:
    <CFNumber 0x6040310 [0xfef3e0]>{value = -97.12345678901235146441, type = kCFNumberFloat64Type}
MPelletier
  • 16,256
  • 15
  • 86
  • 137
Bryan
  • 614
  • 1
  • 8
  • 18

7 Answers7

10

Have you used the NSNumber wrapper?

Configure your store to use NSNumber, instead of float or decimal, and use this to save the coordinates:

[NSNumber numberWithDouble:coordinate.latitude]
//Same for longitude.
Evan Mulawski
  • 54,662
  • 15
  • 117
  • 144
  • Try playing with NSNumberFormatter: http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSNumberFormatter_Class/Reference/Reference.html. Specifically, the significant digits properties. – Evan Mulawski Jan 04 '11 at 00:18
  • I've tried all of these, with no luck. Seems there is an undetermined limit that Core Data uses to store numbers, regardless of type. – Bryan Jan 04 '11 at 14:52
  • Have you attempted to store strings and then convert them back to doubles? – Evan Mulawski Jan 04 '11 at 15:06
  • @ Even: No. That would require a rather large service level change, which I wasn't ready to make, unless its determined I can't store high precision decimals in Core Data. Right now, strings look like my only option. – Bryan Jan 04 '11 at 15:12
1

When Core Data stores data in SQLite, it uses numeric columns. SQLite stores numbers as--at most--8-byte values, whether integer or floating-point. So, while an NSDecimalNumber would be quite happy to accurately represent these coordinate values, round-tripping them through a Core Data decimal attribute backed by SQLite will munge them.

Sixten Otto
  • 14,816
  • 3
  • 48
  • 60
1

Try using the Double data type in Core Data. Since your location coordinates are doubles, makes sense to use the same in Core Data. Though that may be available just now (iOS 5).

Stephen C
  • 455
  • 5
  • 10
0

strongly recommend use NSDecialNumber for storing if you need precise value or compare in your code. you might have different value after store and get value back from core data in double fields.

Jerry Juang
  • 147
  • 2
  • 2
0

since coordinate ranges are well-defined, you can add a few digits of accuracy (compared to double) by using a 64 bit int representation (or even multiple).

in reality, your sources and targets may not make use of or provide this much accuracy so... there may not be much to gain.

justin
  • 104,054
  • 14
  • 179
  • 226
  • I need the values to be exactly what I put into Core Data (ie, if its 22 decimal places going in, it needs to be 22 coming back out). If double/float/decimal won't allow me that, I'll be forced to use NSString. – Bryan Jan 03 '11 at 20:53
  • if you need that level of accuracy, a floating point representation will not suffice. my answer will work if you know the maximum number of digits you'll need to represent in all cases (or have some logical maximum) - this number could be 8, 143, or any finite number of digits - you just use a fixed number of ints to represent the number to that degree of accuracy. otherwise, a string is a simple solution. – justin Jan 03 '11 at 21:03
  • NSStrings might be my solution. However, I'm still looking for the reason why Core Data does this. I've found with a simple test app, that it "appears" to store it fine the first time. However, when I restart the app, the value then is truncated. – Bryan Jan 03 '11 at 21:15
  • NSDecimalNumber has adequate storage to represent 22 decimal places - the others (float,double) do not. if it is stored as an NSDecimalNumber, and you've proven that the print representations support that degree of precision then idk what to say either. perhaps it is worth comparing the result of `decimalValue`. i don't see anything in the docs that says the value may be truncated when archived. as a sanity check: you are defining the CD attribute as Decimal, rather than another numeric representation? obvious, but this is one way to introduce the truncation. – justin Jan 03 '11 at 22:37
  • @ Justin: Yes, I am defining the type as NSDecimalNumber for the CD NSManagedObject class. – Bryan Jan 04 '11 at 14:54
0

I believe the truncation problem could be on the logging, not on the actual data stored in Core Data.

Can you confirm by posting the code you are using to log the output?

I say this because I've noticed that when logging some of my longer NSString fields, Core Data description will only display ~50 characters or so, which might lead you to think it is truncating the data, but it's actually just truncating the description of it.

lkraider
  • 4,111
  • 3
  • 28
  • 31
0

In your data model editor, make sure the types for your lat/long fields are set to double. Otherwise CoreData will do the conversion for you, and the result will be not what you expect (in this case, the decimals will get dropped).

TotoroTotoro
  • 17,524
  • 4
  • 45
  • 76