可可 - 我发现了我认为是NSDecimalNumber的错误 [英] cocoa - I've discovered what I think is a bug with NSDecimalNumber

查看:88
本文介绍了可可 - 我发现了我认为是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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆