【问题标题】:Compare NSDecimalNumber to NSNumber gets wrong result比较 NSDecimalNumber 和 NSNumber 得到错误的结果
【发布时间】:2018-05-28 13:28:49
【问题描述】:

代码很简单,可以复现。

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

isEqualToNumber: 总是返回YES,即使我将d1@6560601600245628930 等其他数字进行比较...有什么想法吗?是bug吗?

【问题讨论】:

  • 我认为这里正在对对象的类型进行比较。试试号码 6560601600245。
  • 在比较 NSNumberNSDecimalNumber 时,这似乎是一个精度问题。如果两个值都是NSDecimalNumber,您将得到正确的结果。如果数字中的数字少一位,则使用当前代码得到正确的结果。
  • 对不起,我的意思是如果数字少 3 位,您当前的代码就可以了。这意味着它适用于 16 位数字,但不能更多。这本质上是double 的精度,所以看起来在比较NSNumber 时,比较的值是double

标签: ios objective-c nsnumber nsdecimalnumber


【解决方案1】:

分析

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

作为NSNumber d1 将其类型报告为double - 即CFNumberGetType() 返回kCFNumberDoubleType - 并且给定double NSNumbercompare: 将两个值比较为@987654339 @。

您的第一个值 (decimalNumberWithString:@"6560601600245628933") 以 NSDecimalNumber 的形式存储而不会造成重大损失,但其有效数字比 double 多,并且转换会丢失精度。

NSNumber 将您的第二个值 (@(6560601600245628934)) 存储为 64 位整数 (kCFNumberSInt64Type) 不会丢失精度,但转换为 double 时会丢失精度。

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

解决方法

变化:

@(6560601600245628934)

到:

[NSDecimalNumber numberWithLongLong:6560601600245628934LL]

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

错误或功能?

它可能被归类为 文档 错误,因为我还没有发现任何地方都记录了它(这远非结论性!)将与 doubles 进行比较。在bugreport.apple.com 提交错误报告,看看他们怎么说。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-19
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    相关资源
    最近更新 更多