2016-06-21 50 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

相關問題