NSDecimalNumber 返回错误的 uint64_t 值
Posted
技术标签:
【中文标题】NSDecimalNumber 返回错误的 uint64_t 值【英文标题】:NSDecimalNumber returning wrong uint64_t value 【发布时间】:2016-05-31 04:51:09 【问题描述】:我的应用程序通过persistentId 记住MPMediaItems,就像一个人一样。它将 persistentId 保存在 JSON 文件中,稍后读取和解析该文件。 NSJSONSerialization 创建一个 NSDecimalNumber 来包含 Id,我的应用稍后在 MPMediaQuery 中使用它来获取 MPMediaItem。
我发现有时会发现错误的 MPMediaItem。当我再四处寻找时,我发现当我将 NSDecimalNumber 转换为 uint64_t 值时,[NSNumber unsignedLongLongValue] 返回了错误的值!
NSDecimalNumber* const songId = _songId;
uint64_t const songIdValue = songId.unsignedLongLongValue;
songId is 1457249251113381177
songIdValue is 1457249251113381120
-or-
songId is 0x1439307919d12d39
songIdValue is 0x1439307919d12d00
什么鬼?看起来低字节在将此 NSDecimalNumber 转换为 uint64_t 时被清除。这是 NSDecimalNumber 的某种正确行为吗?我发现其中有错误吗?
我正在通过将 NSDecimalNumber 从 NSJSONSerialization 转换为字符串并使用 [NSString longLongValue] 将字符串转换为 uint64_t 来解决此问题。
这很可怕,因为我现在似乎必须检查我在 JSON 文件中存储大整数的每个地方,并确保我以这种 NSString-y 方式评估它们。
【问题讨论】:
我在这里找到了一条评论,说 NSDecimalNumber 在转换为 uint64_t 之前先转换为双精度数。因此,任何超过 53 的有效位都会被清除,正如我在这里看到的那样。令人难以置信的是,Apple 让这一切站稳了脚跟! NSJsonSerialization 在为整数而不是 NSNumber 选择此类时出错。我打算将我的 JSON 解析切换到 JSONKit,我建议其他人也这样做。 在他的评论中,Christopher 可能指的是this answer to NSDecimalNumber and large unsigned long long (64-bit) integers 【参考方案1】:如果你想保持最大的精度,你可以:
仅适用于 NSDecimalNumbers,
当您将 NSDecimalNumber 的值传输到另一个不是 NSDecimalNumber 的变量时,请使用 NSString。 [NSDecimalNumber longLongValue] 或 [NSDecimalNumber doubleValue] 等方法不够具体。
NSDecimalNumber *songId;
uint64_t songIdValue;
NSString *intermediateStr;
songId = [NSDecimalNumber decimalNumberWithString:@"1457249251113381177"];
intermediateStr = songId.stringValue;
songIdValue = intermediateStr.longLongValue;
为什么使用字符串比其他方法更精确?我不知道。但是 songIdValue 包含正确的值,没有任何损失。
【讨论】:
以上是关于NSDecimalNumber 返回错误的 uint64_t 值的主要内容,如果未能解决你的问题,请参考以下文章
比较 NSDecimalNumber 和 NSNumber 得到错误的结果
从 NSDecimalNumber 中删除负号 (-) 给我一个错误
使用 numberFromString 生成 NSDecimalNumber 时如何在没有分数错误的情况下获得舍入值?
NSDecimalNumber(x).intValue 返回 -2、0、15 和 199,具体取决于 x 中的小数位数 (x = 199.999...5)