NSDecimalNumber与NSNumber比较返回错误结果问题咨询
为什么NSDecimalNumber与大整数NSNumber比较时isEqualToNumber:总是返回YES?
这个问题其实不是bug,而是由浮点数精度限制和isEqualToNumber:的比较逻辑共同导致的,我来给你拆解清楚:
首先看你提供的代码:
NSDecimalNumber *d1 = [NSDecimalNumber decimalNumberWithString:@"6560601600245628933"]; BOOL res = [d1 isEqualToNumber:@(6560601600245628934)]; NSLog(@"%@", @(res));
核心原因1:大整数无法被double精确表示
你用到的数字6560601600245628933和6560601600245628934都远大于2^53(也就是9007199254740992)——这是double类型能精确表示的最大整数。
当你用@(...)语法创建NSNumber时,编译器会把超出2^53的整数自动转换为double类型存储。但double的尾数只有53位,无法区分这些大整数之间的微小差异(比如差1),所以@(6560601600245628933)和@(6560601600245628934)实际上存储的是同一个double值。
核心原因2:isEqualToNumber:的跨类型比较逻辑
isEqualToNumber:方法在比较不同类型的数字对象时(比如NSDecimalNumber和普通NSNumber),会尝试将两者转换为同一种类型来对比。这里它会把NSDecimalNumber转换为double类型,再和NSNumber里的double值比较——既然两者的double值完全相同,自然会返回YES。
如何正确解决?
如果你需要精确比较这类超大整数,必须保证所有参与比较的数字都用NSDecimalNumber来创建,这样就能避免浮点数精度丢失:
NSDecimalNumber *d1 = [NSDecimalNumber decimalNumberWithString:@"6560601600245628933"]; NSDecimalNumber *d2 = [NSDecimalNumber decimalNumberWithString:@"6560601600245628934"]; BOOL res = [d1 isEqualToNumber:d2]; NSLog(@"%@", @(res)); // 这里会返回NO,符合预期
或者,如果你必须使用NSNumber,也可以用initWithDecimal:方法基于NSDecimal来创建,确保精度不丢失。
内容的提问来源于stack exchange,提问作者KudoCC
相关产品推荐
相关产品推荐

