比较两个相等的无符号long在C中的计算结果为false

时间:2016-06-21 20:25:48

标签: c comparison long-integer unsigned

我是C的新手并且玩弄它。所以我最终实现了斐波那契代码(迭代和递归)。我写了一个测试函数,它应该给我一个绿色(我的实现工作)或红色。它说我得到了正确的返回值,但它的状态是红色的。这两个值应该是无符号长的。我正在使用make

编译OSX
#include <stdio.h>

unsigned long fibonacci(unsigned long n);
void test_fibonacci(unsigned long n, unsigned long assertion);

int main(int argc, char* argv[])
{
    test_fibonacci(1, 1);
    test_fibonacci(2, 1);
    test_fibonacci(3, 2);
    test_fibonacci(10, 55);
    return 0;
}

unsigned long fibonacci(unsigned long n)
{
    unsigned long result = 1;
    unsigned long lastResult;
    for (unsigned long i = 2; i <= n; i++)
    {
        // save the current result to save it as the lastResult after this iteration
        unsigned long lastResultTmp = result;
        result = lastResult + result;
        lastResult = lastResultTmp;
    }
    return result;
}

void test_fibonacci(unsigned long n, unsigned long assertion)
{
    printf(
        "fibonacci(%lu): %lu    | %s | asserted: %lu\n",
        n,
        fibonacci(n),
        (fibonacci(n) == assertion) ? "green" : "red",
        assertion
    );
}

我的Makefile

CFLAGS=-Wall -g

all: main

clean:
    rm -f main
    rm -Rf *.dSYM

输出:

fibonacci(1): 1    | green | asserted: 1
fibonacci(2): 1    | red | asserted: 1
fibonacci(3): 2    | red | asserted: 2
fibonacci(10): 55    | red | asserted: 55

3 个答案:

答案 0 :(得分:3)

我没有得到你的输出。这就是我所看到的:

fibonacci(1): 1    | green | asserted: 1
fibonacci(2): 2    | red | asserted: 1
fibonacci(3): 4    | red | asserted: 2
fibonacci(10): 3353    | red | asserted: 55

我很好奇为什么,所以我和valgrind一起跑了。这很快就出现了这个错误:

==5619== Conditional jump or move depends on uninitialised value(s)
==5619==    at 0x4005E7: test_fibonacci (fibonacci.c:31)
==5619==    by 0x400559: main (fibonacci.c:9)

所以看起来这与未初始化的变量读取有关,这会给你错误的值。这最终指向我们:

unsigned long fibonacci(unsigned long n)
{
    unsigned long result = 1;
    unsigned long lastResult; // <---- LOOK HERE
    for (unsigned long i = 2; i <= n; i++)
    {
        // save the current result to save it as the lastResult after this iteration
        unsigned long lastResultTmp = result;
        result = lastResult + result;
        lastResult = lastResultTmp;
    }
    return result;
}

请注意lastResult未初始化,但在行

中读取
 result = lastResult + result;

所以看起来你需要初始化那个值。由于该值对应于先前的斐波纳契数,因此应初始化为零。这样做会导致所有测试通过。

现在,究竟发生了什么导致它看起来像你得到了正确答案但仍然失败了?请注意,您在测试代码中调用了fibonacci两次。我的猜测是第一次调用fibonacci - 被打印的那个 - 只是通过纯粹的随机机会碰巧正常工作,因为由于某种原因,第一次调用lastResult中的值恰好为0。但是,我猜测第二次fibonacci的调用 - 与预期结果进行比较的那个 - 没有返回与第一次调用相同的值,因为,无论出于何种原因,lastResult的值在第二次调用时都不是0。这是关于未定义行为的事情 - 像这样奇怪的事情可能会发生!

答案 1 :(得分:1)

斐波那契(1):1 |绿色|断言:1

斐波那契(2):3076653057 |红色|断言:1

斐波那契(3):3076653058 |红色|断言:2

斐波那契(10):1526988855 |红色|断言:55

我将此输出提供给您的代码。我认为这是因为未初始化的变量lastResult。因为当我用0初始化它时,我得到了正确的结果。

答案 2 :(得分:1)

OP see comment

这显示了测试中的微妙弱点。调用(fibonacci(n) == assertion)时,它提供了正确的答案。当fibonacci(n)被呼叫时,它提供了错误的答案。您的测试代码每次测试而不是一次调用// unsigned long lastResult; // bad unsigned long lastResult = 0; // good 两次的弱点。由于您的代码有一个未初始化的变量:@templatetypedef

unsigned long f = fibonacci(n);  
printf("fibonacci(%lu): %lu    | %s | asserted: %lu\n", 
    n, f, (f == assertion) ? `"green" : "red", assertion;

使用UB(未定义的行为) - 这是可能的。

测试代码应该调用测试函数一次

test_fibonacci()

然后至少,对于错误的test_fibonacci(),更有可能获得一致的结果。

OTOH,这个弱点指出可能是一个强项,如果测试每个循环只调用feesPayer一次,UB可能不会以糟糕的方式表现出来。