2

我有一些方法接收 afloat作为参数,并检查这个浮点数是否在数组中。为此,我首先将 float 转换为NSNumber. 这是我的代码的可测试简化:

float aFloat = 0.3;
NSNumber *aNSNumber = @(aFloat);

NSArray *anArray = @[@(0.0), @(0.3), @(1.0)];
NSLog(@"%d", [anArray containsObject:aNSNumber]);

此代码将记录0(即NO),因此它表示0.3不在anArray. 如果aFloat是“圆形”数字,例如0.00.51.0,则测试有效并记录1(即YES)。除此之外的任何数字,如0.3上述,都失败了。

另一方面,如果我们更改aFloat为 a double,它可以工作。或者,如果我们改成anArray这样:

NSArray *array = @[[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.3], [NSNumber numberWithFloat:1.0]];

它也有效。我假设 NSNumber@()符号创建了一个numberWithDouble:.

但是,我的问题是,即使aFloat是 a ,它也不应该工作float吗?因为我无论如何都要通过将它保存在“转换”它aNSNumber......而且它不应该自动识别 thefloat 0.3和 thedouble 0.3实际上是相同的数字吗?另外,为什么“圆形”数字仍然有效?

4

3 回答 3

3

@(0.3)使用-numberWithDouble:因为0.3有类型double。如果你写了@(0.3f),那么它将使用-numberWithFloat:.

既不floatdouble不能准确地存储 0.3。(这类似于以十进制形式写 1/3 的问题——你不能完全使用有限的数字来做到这一点。)相反,你得到float最接近 0.3 和double最接近 0.3 的值。这两个数字不相等,所以-containsObject:找不到匹配项。

float和都double可以准确地存储 0.0 和 1.0,因此两种转换都会给您相同的结果并-containsObject:成功。

于 2013-08-26T20:15:09.613 回答
1

@(0.3)in the是anArray一个double包裹在一个NSNumber. 当然你aFloat是一个float包裹在一个NSNumber.

尝试以下两种可能的更改之一:

1)float aFloat改为double aFloat

或者

2 )更改@(0.3)anArray@(0.3f)

于 2013-08-25T06:03:43.153 回答
1

您可以使用以下代码段可视化 0.3 和 0.3f 之间的差异:

NSLog(@"%.20f %.20f", 0.3, 0.3f);

我的调试器显示:0.29999999999999998890 0.30000001192092895508

有趣的是,“0.3”似乎比“0.3f”更准确。无论如何,我推测编译器可能会在将其转换为浮点数之前先将直接的 0.3 作为双精度数,而 0.3f 规范立即是浮点数。

要观察的另一件事是您是否这样做:

NSArray *anArray = @[@(0.0), aNSNumber, @(1.0)];

containsObject 调用将成功。也许编译器将浮点数转换为它在 aFloat 声明和文字之间内部使用的任何内容的路径存在一些差异。这里只是推测...

一般来说,我不喜欢用浮点数或双精度数来测试是否相等。精度问题可以很容易地通过你循环。

于 2013-08-25T14:53:40.517 回答