我知道UIKit使用CGFloat,因为它是分辨率无关的坐标系。

但每次我想检查frame.origin.x是否为0时,我都觉得很恶心:

if (theView.frame.origin.x == 0) {
    // do important operation
}

当与==,<=,>=,<,>比较时,CGFloat是否容易出现假阳性? 它是一个浮点数,它们有不精确的问题:例如0.0000000000041。

Objective-C在比较时是否会在内部处理这个或者是否会发生原点。读作0的X不与0比较为真?


当前回答

我认为正确的做法是将每个数字声明为一个对象,然后在该对象中定义三个东西:1)相等运算符。2)一个setAcceptableDifference方法。3)价值本身。如果两个值的绝对差小于设置为可接受的值,则相等运算符返回true。

您可以对对象进行子类化以适应该问题。例如,如果1到2英寸之间的圆金属棒的直径相差小于0.0001英寸,则可以认为它们的直径相等。因此,您可以使用参数0.0001调用setAcceptableDifference,然后放心地使用相等操作符。

其他回答

正确的问题是:如何在Cocoa Touch中比较分数?

正确答案:CGPointEqualToPoint()。

另一个问题:两个计算值是否相同?

答案贴在这里:他们不是。

如何检查它们是否接近?如果你想检查它们是否接近,那么不要使用CGPointEqualToPoint()。但是,不要检查它们是否接近。做一些在现实世界中有意义的事情,比如检查一个点是否超出了一条线,或者一个点是否在一个球体内。

你可以使用这样的代码来比较float和0:

if ((int)(theView.frame.origin.x * 100) == 0) {
    // do important operation
}

这将与0.1的精度进行比较,在这种情况下,这对CGFloat来说足够了。

我想给出一个和其他人不一样的答案。他们很好地回答了你的问题,但可能不是你需要知道的或你真正的问题是什么。

图形中的浮点数很好!但是几乎没有必要直接比较浮点数。你为什么要这么做?图形使用浮点数来定义间隔。比较浮动是否在浮动所定义的区间内总是定义良好的,只需要保持一致,而不需要精确或精确!只要可以分配一个像素(这也是一个间隔!),这就是所有的图形需求。

所以如果你想测试你的点是否在a [0..]宽度[范围,这很好。只要确保你对包含的定义是一致的。例如,总是定义内部是(x>=0 && x < width)。这同样适用于交叉测试或命中测试。

但是,如果您滥用图形坐标作为某种标志,例如查看窗口是否停靠,则不应该这样做。使用一个独立于图形表示层的布尔标志。

另一个可能需要记住的问题是,不同的实现做事情的方式不同。我非常熟悉的一个例子是索尼Playstation 2上的FP单元。与任何X86设备中的IEEE FP硬件相比,它们有显著的差异。引用的文章提到完全缺乏对inf和NaN的支持,而且情况变得更糟。

不太为人所知的是我后来所知道的“一位乘法”错误。对于float x的特定值:

    y = x * 1.0;
    assert(y == x);

断言将失败。在一般情况下,有时,但不总是,在Playstation 2上FP相乘的结果比等效的IEEE尾数少一位。

我的观点是,您不应该假设将FP代码从一个平台移植到另一个平台会产生相同的结果。任何给定的平台都是内部一致的,因为结果在该平台上不会改变,只是它们可能与另一个平台不一致。例如,X86上的CPython使用64位双精度来表示浮点数,而Cortex MO上的CircuitPython必须使用软件FP,并且只使用32位浮点数。不用说,这会引起差异。

我40多年前学到的一句话今天依然适用。“在计算机上做浮点运算就像移动一堆沙子。每次你做任何事,都会留下一点沙子,捡起一点泥土。”

Playstation是索尼公司的注册商标。

我使用下面的比较函数来比较小数点后的数位:

bool compare(const double value1, const double value2, const int precision)
{
    int64_t magnitude = static_cast<int64_t>(std::pow(10, precision));
    int64_t intValue1 = static_cast<int64_t>(value1 * magnitude);
    int64_t intValue2 = static_cast<int64_t>(value2 * magnitude);
    return intValue1 == intValue2;
}

// Compare 9 decimal places:
if (compare(theView.frame.origin.x, 0, 9)) {
    // do important operation
}