Objective C奇怪的十进制转长整型转换

6
NSLog(@"%llu\n\n", ULONG_LONG_MAX);

NSDecimalNumber *decimal = [NSDecimalNumber decimalNumberWithString:@"154550038129946620"];
NSLog(@"%@", decimal);
NSLog(@"%llu\n\n", [decimal unsignedLongLongValue]);

decimal = [NSDecimalNumber decimalNumberWithString:@"154550038129946628"];
NSLog(@"%@", decimal);
NSLog(@"%llu", [decimal unsignedLongLongValue]);

两个值都小于ULONG_LONG_MAX。但是,我们在输出中看到的是:

2012-01-05 17:41:55.879 test[1276:207] 18446744073709551615

2012-01-05 17:41:55.969 test[1276:207] 154550038129946620
2012-01-05 17:41:56.095 test[1276:207] 154550038129946624

2012-01-05 17:41:56.096 test[1276:207] 154550038129946628
2012-01-05 17:41:56.096 test[1276:207] 154550038129946624

我做错了什么?我不知道如何解释这种行为。
1个回答

5

NSDecimalNumber缺少unsignedLongLongValue方法,因此从 NSNumber 继承了默认的实现。获取NSDecimalNumber值的唯一方法是获取一个NSDecimal结构或一个double。将NSDecimalNumber转换为double的过程中引入了转换错误。


我一开始没有理解,于是发布了自己的答案,但现在我明白了,你的答案和我的一样。对于其他像我一样没有完全理解的人来说,“NSDecimalNumber”内部的十进制数被转换为double,然后再转换为unsigned long long。无论如何,我认为这是一个基本的SDK错误。 - Alexander N.
@AlexanderN。我不同意这是基本的SDK缺陷:如果你在NSDecimalNumber范围内,你可以获得可靠的精度,这对于SDK设计者来说是最重要的。转换到其他类型只是为了方便;使用它们需要理解由于表示方式的差异可能会丢失一些精度。 - Sergey Kalinichenko
我理解这个问题。但是你不觉得这有点奇怪吗 - 把整数(在此情况下)强制转换为长整型,丢失精度,就像浮点数转换为整数一样? - Alexander N.
1
@AlexanderN。我同意这是设计上的一个缺陷:NSDecimalNumber的架构师本可以提供更直观的行为,特别是因为架构已经提供了一切他们需要使其正确的东西。他们所需要做的就是覆盖一个已经存在的方法。但这并不足以称之为根本性的问题。 - Sergey Kalinichenko
是的,也许你是对的,我可能对这个问题过于兴奋了 :) 好吧,至少它足够奇怪,在处理小数时要记在心里。 - Alexander N.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接