0

我是单元测试的新手,我决定编写一个简单的计算器来研究这些概念,但我遇到了一个对我来说毫无意义的问题。STAssertEquals 因 2 个显然相同的双精度值而失败。我得到的错误是这个:'-2.89'应该等于'-2.89':

执行计算的代码是:

- (double)calculateOperation:(int)operation numberA:(double)numA numberB:(double)numB
{
    double result = 0;

    switch(operation)
    {
        case addition:
            result = numA + numB;
            break;

        case subtraction:
            result = numA - numB;
            break;

        case multiplication:
            result = numA * numB;

        default:
            break;
    }

    return result;
}

测试是

- (void)testSubtraction
{
    //Two double positive values
    double test1 = [calculator calculateOperation:subtraction numberA:4.45 numberB:7.34];

    STAssertEquals(test1, -2.89, nil);
}

我尝试了不同的值,似乎只有一定范围的值会导致 STAssertEquals 失败。

但是,如果我执行 STAssertEquals((4.45 - 7.34), -2.89, nil) 它可以正常工作。

我真的不知道怎么了。

4

1 回答 1

2

考虑以下设置:

double a = 4.45;
double b = 7.34;
double result = a - b;
double testVal = -2.89;

此时,如果您查看resultvs.内存中的实际值,testVal您将看到以下内容:

(lldb) p/x *(uint64_t*)&testVal
(uint64_t) $1 = 0xc0071eb851eb851f
(lldb) p/x *(uint64_t*)&result
(uint64_t) $2 = 0xc0071eb851eb851e

因此,您可以看到确实存在差异,这可能是由于减法运算中的舍入,在 的有效数字的最后一位result与我们输入的文字之间testVal。当格式化代码将本机二进制表示转换为十进制时,这种差异可能并不明显,因为这些转换并不总是准确的,但它仍然会影响这两个值的文字相等性。

实际上,您可能希望在STAssertEqualsWithAccuracy此处使用,为适合您的应用程序的准确性选择一些值。(对于图形工作,我通常使用 1e-6,但您的里程可能会有所不同。)另外,由于一切都是double,因此您不需要在这里显式转换。编译器将不带后缀的十进制数字文字解释为 a double(如果您想float在十进制数字文字后面加上 F,并且如果您想在long double后面加上 L。即 -2.89F 或 -2.89L)

值得重申:尽管许多人喜欢在十进制参考框架中考虑浮点数(因为这是我们大多数人学习算术的方式),但这不是它们的存储方式,而不是“它们的工作方式”。如果您不期望它们表现得像以 10 为底的数字,那么您的失望就会少得多。这是一个典型的例子。

于 2013-06-11T11:46:00.883 回答