2016-06-21 14 views
2

我是C的新手,并且玩弄它。所以我最终实现了fibonacci代码(迭代和递归)。我写了一个测试函数,它应该给我一个绿色(我的实现工程)或红色。它说我得到正确的返回值,但它的状态是红色的。这两个值应该都是无符号的。我编译OSX上用make比较两个相等的无符号long在C中的结果为false

#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

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

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。这是关于未定义行为的事情 - 这种奇怪的事情可能发生!

+0

非常感谢!这是完全正确的。由于第一个斐波那契数字,我将for循环设置为3和lastResult为1。这解决了我的问题。我完全必须检查valgrind。 – noeden

+0

@noeden当你开始时,Valgrind是一个很棒的工具。我的建议是(1)用警告设置进行编译,(2)将警告转化为错误,(3)在Valgrind中运行程序。你会惊讶你会以这种方式捕捉到多少错误。 :-) – templatetypedef

+0

同意需要初始化'lastResult',因为不这样做会导致UB。然而,我怀疑别的东西导致OP得到“正确”的答案,但是失败的比较。 Hmmmm。 UB是UB。 - > Aha,'fibonacci()'每隔一段时间报告OP的正确答案。 – chux

1

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

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

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

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

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

1

OP see comment

这显示了测试中的一个微妙弱点。当fibonacci(n)被调用时,它提供了正确的答案。当调用(fibonacci(n) == assertion)时,它提供了错误的答案。测试代码每测试一次而不是一次调用fibonacci(n)两次的弱点。当你的代码有一个未初始化的变量:@templatetypedef

// unsigned long lastResult; // bad 
unsigned long lastResult = 0; // good 

随着UB(未定义行为) - 这是可能的。


测试代码应该叫测试功能一次

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

那么至少,与错误的test_fibonacci(),更有可能获得一致的结果。


OTOH,这弱点指出,可能是一个力量在有测试只叫test_fibonacci()每一次循环中,UB可能没有一个坏的方式表现出来。

+1

谢谢!我会改变这一点。 – noeden

相关问题