0

私は単体テストが初めてで、概念を研究するために簡単な電卓を書くことにしましたが、意味のない問題に遭遇しました。STAssertEquals は、明らかに同じである 2 つの double 値に対して失敗しています。私が得ているエラーはこれです: '-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;

resultこの時点で、 vsのメモリ内の実際の値をtestVal見ると、次のことがわかります。

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

したがって、おそらく減算操作での丸めにより、 の仮数部の最後のビットと、 にresult入力したリテラルに違いがあることがわかりますtestVal。書式設定コードがネイティブ バイナリ表現を 10 進数に変換する場合、この違いは明らかではない場合があります。これらの変換は常に正確であるとは限らないためですが、これら 2 つの値の文字どおりの同等性には依然として影響します。

STAssertEqualsWithAccuracy実際には、アプリケーションに適した精度の値を選択して、ここで使用することをお勧めします。(グラフィックス作業では、通常 1e-6 を使用しますが、マイレージは異なる場合があります。) また、すべてが であるためdouble、ここで明示的なキャストは必要ありません。サフィックスのない 10 進数値リテラルは、コンパイラによって として解釈されdoubleます ( float10 進数値リテラルの後に F が必要な場合、およびlong doubleL が必要な場合は、-2.89F または -2.89L)。

繰り返しますが、多くの人は浮動小数点数を 10 進数の参照フレームで考えるのが好きですが (これは私たちのほとんどが算術を学んだ方法だからです)、それは浮動小数点数がどのように格納されるかではなく、「どのように機能するか」でもありません。基数 10 の数値のように振る舞うことを期待しなければ、失望することはほとんどありません。これはその典型的な例です。

于 2013-06-11T11:46:00.883 に答える