简体   繁体   中英

Comparing two equal unsigned long in C evaluates to false

I am new to C and playing around with it. So I ended up in implementing the fibonacci code (iterative and recursive). I wrote a test function which should give me a green (my implementation works) or red. It says that I get the right return value but it's state is red. The two values should be both unsigned long. I am compiling on OSX with make

#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
    );
}

My Makefile

CFLAGS=-Wall -g

all: main

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

Output:

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

I'm not getting the output that you are. Here's what I'm seeing:

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

I was curious why, I so I ran it with valgrind. That quickly popped up this error:

==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)

So it looks like this has to do with an uninitialized variable getting read, which would give you the wrong values. That ultimately points us here:

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;
}

Notice that lastResult is uninitialized, but is read in the line

 result = lastResult + result;

So it looks like you need to initialize that value. Since that value corresponds to the previous Fibonacci number, you should initialize to zero. Doing that causes all the tests to pass.

Now, what exactly happened that caused it to look like you were getting the right answer but still failing? Notice that you called fibonacci twice in your testing code. My guess is that the first call to fibonacci - the one that got printed - just by sheer random chance happened to work correctly because for some reason the value in lastResult on the first call happened to be 0. However, I'm going to guess that the second call to fibonacci - the one that got compared against the expected result - did not return the same value as the first call because, for whatever reason, the value of lastResult wasn't 0 when that second call was made. That's the thing about undefined behavior - weird stuff like that can happen!

fibonacci(1): 1 | green | asserted: 1

fibonacci(2): 3076653057 | red | asserted: 1

fibonacci(3): 3076653058 | red | asserted: 2

fibonacci(10): 1526988855 | red | asserted: 55

I am getting this output to your code. And I think this is because of the uninitialized variable lastResult. Because when I initialized it with 0 I got the correct result.

OP see comment .

This shows a subtle weakness in your test. When fibonacci(n) was called, it provided the correct answer. When (fibonacci(n) == assertion) was call it provided the wrong answer. The weakness it that your test code called fibonacci(n) twice per test rather than once. As your code had an uninitialized variable: @templatetypedef

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

With UB (undefined behavior) - that is possible.


Test code should have called the test function once :

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

Then at least, with the errant test_fibonacci() , far more likely to get consistent results.


OTOH, this weakness pointed out could be a strength in that had the test only called test_fibonacci() once per loop, the UB may not have manifested itself in a bad way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM