将 NSDecimalNumber 与 NSNumber 进行比较会得到错误的结果

Compare NSDecimalNumber to NSNumber gets wrong result

代码简单,可以复现

NSDecimalNumber *d1 = [NSDecimalNumber decimalNumberWithString:@"6560601600245628933"];
BOOL res = [d1 isEqualToNumber:@(6560601600245628934)];
NSLog(@"%@", @(res));

isEqualToNumber: 总是 returns YES,即使我将 d1@6560601600245628930 等其他数字进行比较......有什么想法吗?这是一个错误吗?

分析

NSDecimalNumbercompare:(由 isEqualToNumber: 调用)检查其参数(此处为 @(6560601600245628934))是否为另一个 NSDecimalNumber,如果不是求助于 NSNumbercompare:NSNumberNSDecimalNumber 的超类)。

作为 NSNumber d1 报告其类型为 double – 即 CFNumberGetType() returns kCFNumberDoubleType – 并给出 double NSNumbercompare: 将两个值比较为 double.

您的第一个值 (decimalNumberWithString:@"6560601600245628933") 以 NSDecimalNumber 的形式存储而没有宝贵的损失,但比 double 具有更多的有效数字并且转换会失去精度。

您的第二个值 (@(6560601600245628934)) 由 NSNumber 存储为 64 位整数 (kCFNumberSInt64Type),没有精度损失,但在转换为 double 时会损失精度。

对于您尝试过的变体,表示为 double 的两个数字是相同的。

解决方法

变化:

@(6560601600245628934)

至:

[NSDecimalNumber numberWithLongLong:6560601600245628934LL]

直接从您的整数创建一个 NSDecimalNumber 值。这将导致 isEqualToNumber: 的两个参数都是 NSDecimalNumber 并且在比较时不会丢失精度。

错误或功能?

它可能被归类为 文档 错误,因为我没有在任何地方找到它的记录(这远非决定性的!)比较将与 double秒。在 bugreport.apple.com 提交错误报告,看看他们怎么说。