可可 - 我发现了我认为是NSDecimalNumber的错误 [英] cocoa - I've discovered what I think is a bug with NSDecimalNumber
问题描述
这是一个简单的代码,显示我认为处理双数字时的错误...
Here is a simple code that shows what I think is a bug when dealing with double numbers...
double wtf = 36.76662445068359375000;
id xxx = [NSDecimalNumber numberWithDouble: wtf];
NSString *myBug = [xxx stringValue];
NSLog(@"%.20f", wtf);
NSLog(@"%@", myBug);
NSLog(@"-------\n");
终端将显示两个不同的数字
the terminal will show two different numbers
36.76662445068359375000
和
36.76662445068359375000 and
36.76662445068359168
36.76662445068359168
这是一个错误还是我错过了什么?
Is this a bug or am I missing something?
如果第二个数字被舍入,那是一个非常奇怪的四舍五入......
if the second number is being rounded, it is a very strange rounding btw...
= = = = = = = = = =
我正在编辑原始问题以再包含一个WTF错误...
I am editing the original question to include one more WTF bug...
试试这个:
修改原始数字并将其截断为10位十进制数......所以......
modify the original number and truncate it on 10 decimal digits... so...
double wtf = 36.76662445068359375000;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:10];
NSString *valueX = [formatter stringFromNumber:[NSDecimalNumber numberWithDouble:wtf]];
[formatter release];
NSLog(@"%@", valueX);
现在答案是36.7666244507
the answer now is 36.7666244507
现在该值是一个包含10位十进制数字的字符串...现在让我们将其转换回双倍
now the value is a string with 10 decimal digits... now lets convert it back to double
double myDoubleAgain = [valueX doubleValue];
NSLog(@"%.20f", myDoubleAgain);
答案是36.76662445070000018177 ??????
the answer is 36.76662445070000018177 ??????
myDoubleAgain现在有更多数字!!!!
myDoubleAgain has now more digits!!!!
推荐答案
通常情况下,我是那个进来并解释的人对于他们输入的数字不能表示为浮点数的人,以及舍入错误的位置,等等等等等。
Normally, I'm the one who comes in and explains to people that the number they entered is not representable as a floating-point number, and where the rounding errors are, blah blah blah.
这个问题比我们通常看到的,它正好说明了浮动点是不精确的,阅读'每个计算机科学家应该知道的...... 'lolz的人群智慧有什么问题。
This question is much more fun than what we usually see, and it illustrates exactly what's wrong with the crowd wisdom of "floating point is inexact, read 'what every computer scientist should know...' lolz".
36.76662445068359375
不只是任何19位十进制数。它恰好是一个19位十进制数,也可以在双精度二进制浮点中精确表示。因此,初始转换隐含在:
36.76662445068359375
is not just any 19-digit decimal number. It happens to be a 19 digit decimal number that is also exactly representable in double precision binary floating point. Thus, the initial conversion implicit in:
double wtf = 36.76662445068359375000;
是准确的。 wtf
包含 b100100.11000100010000011
,并且未进行舍入。
is exact. wtf
contains exactly b100100.11000100010000011
, and no rounding has occurred.
NSDecimalNumber的规范表示它将数字表示为38位十进制尾数和范围为[-127,128]的十进制指数,因此<$ c $中的值c> wtf 也可以完全表示为NSDecimalNumber。因此,我们可以得出结论 numberWithDouble
没有提供正确的转换。虽然我找不到声称这个转换例程被正确舍入的文档,但没有充分的理由不这样做。 这是一个真正的错误,请报告。
The spec for NSDecimalNumber says that it represents numbers as a 38 digit decimal mantissa and a decimal exponent in the range [-127,128], so the value in wtf
is also exactly representable as an NSDecimalNumber. Thus, we may conclude that numberWithDouble
is not delivering a correct conversion. Although I cannot find documentation that claims that this conversion routine is correctly rounded, there is no good reason for it not to be. This is a real bug, please report it.
我注意到iPhoneOS上的字符串格式化程序似乎提供了正确的舍入结果,所以你可以通过首先将double格式化为38位精度的字符串然后使用<$ c来解决这个问题。 $ C> decimalNumberWithString 。不理想,但它可能适合你。
I note that the string formatters on iPhoneOS seem to deliver correctly rounded results, so you can probably work around this by first formatting the double as a string with 38 digit precision and then using decimalNumberWithString
. Not ideal, but it may work for you.
这篇关于可可 - 我发现了我认为是NSDecimalNumber的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!