由fibonacci数列看C语言的补码

首先看一个计算fibonacci数列的demo:

root@root:~/dsa/d_c$ cat fib_iterate.c
#include <stdio.h>
#include <time.h>

int main(int argc, char const *argv[]){
    time_t start_time, end_time;
    double time_diff;
    const int n = 64;
    for(int i = 1; i < n; i++){
        time(&start_time);

        int pre = 0;
        int res = 1;
        int ope = i;
        while (0 < ope--) {
            res = res + pre;
            pre = res - pre;
        }

        time(&end_time);
        time_diff = difftime(end_time, start_time);
        printf("fib(%d) = %d, 耗时%fs\n", i, res, time_diff);
    }
}

root@root:~/dsa/d_c$
root@root:~/dsa/d_c$ ./fib_iterate.out 
fib(1) = 1, 耗时0.000000s
fib(2) = 2, 耗时0.000000s
fib(3) = 3, 耗时0.000000s
fib(4) = 5, 耗时0.000000s
fib(5) = 8, 耗时0.000000s
fib(6) = 13, 耗时0.000000s
fib(7) = 21, 耗时0.000000s
fib(8) = 34, 耗时0.000000s
fib(9) = 55, 耗时0.000000s
fib(10) = 89, 耗时0.000000s
fib(11) = 144, 耗时0.000000s
fib(12) = 233, 耗时0.000000s
fib(13) = 377, 耗时0.000000s
fib(14) = 610, 耗时0.000000s
fib(15) = 987, 耗时0.000000s
fib(16) = 1597, 耗时0.000000s
fib(17) = 2584, 耗时0.000000s
fib(18) = 4181, 耗时0.000000s
fib(19) = 6765, 耗时0.000000s
fib(20) = 10946, 耗时0.000000s
fib(21) = 17711, 耗时0.000000s
fib(22) = 28657, 耗时0.000000s
fib(23) = 46368, 耗时0.000000s
fib(24) = 75025, 耗时0.000000s
fib(25) = 121393, 耗时0.000000s
fib(26) = 196418, 耗时0.000000s
fib(27) = 317811, 耗时0.000000s
fib(28) = 514229, 耗时0.000000s
fib(29) = 832040, 耗时0.000000s
fib(30) = 1346269, 耗时0.000000s
fib(31) = 2178309, 耗时0.000000s
fib(32) = 3524578, 耗时0.000000s
fib(33) = 5702887, 耗时0.000000s
fib(34) = 9227465, 耗时0.000000s
fib(35) = 14930352, 耗时0.000000s
fib(36) = 24157817, 耗时0.000000s
fib(37) = 39088169, 耗时0.000000s
fib(38) = 63245986, 耗时0.000000s
fib(39) = 102334155, 耗时0.000000s
fib(40) = 165580141, 耗时0.000000s
fib(41) = 267914296, 耗时0.000000s
fib(42) = 433494437, 耗时0.000000s
fib(43) = 701408733, 耗时0.000000s
fib(44) = 1134903170, 耗时0.000000s
fib(45) = 1836311903, 耗时0.000000s
fib(46) = -1323752223, 耗时0.000000s
fib(47) = 512559680, 耗时0.000000s
...

在计算到46位元素的时候,结果变成了负数,原因是存储结果的变量res是int类型,运行这段代码的机器是64位,在64位机器上,int类型长度为4字节,32bit,取值范围是-(231+1)~231:-2147483648 ~ 2147483647,而fib(46) = fib(45) + fib(44) = 1836311903 + 1134903170 = 2971215073 > 2147483647。
那么,程序给出的-1323752223是如何产生的呢?是由于C语言用于表示负数的补码操作:当要表示一个整数的负数时,将该整数的二进制按位取反再加1。比如3的二进制是00000011,那么-3就表示为11111101。
回到刚才的fibonacci数列,fib(45) = 1836311903, 二进制为01101101011100111110010101011111;
fib(44) = 1134903170, 二进制为01000011101001010011111110000010;俩数相加得10110001000110010010010011100001,可以看到这是一个首位是1,共32的数字,在int类型下会被解释为负数,将这个数减1再按位取反得01001110111001101101101100011111,换算成十进制就是1323752223。
解决方法可以是使用无符号整型unsigned int(0~232, 0~4294967295)存储计算结果:

#include <stdio.h>
#include <time.h>

int main(int argc, char const *argv[]){
    time_t start_time, end_time;
    double time_diff;
    const int n = 64;
    for(int i = 1; i < n; i++){
        time(&start_time);

        int pre = 0;
        unsigned int res = 1;
        int ope = i;
        while (0 < ope--) {
            res = res + pre;
            pre = res - pre;
        }

        time(&end_time);
        time_diff = difftime(end_time, start_time);
        printf("fib(%d) = %u, 耗时%fs\n", i, res, time_diff);
    }
}

或使用长整型long int:

#include <stdio.h>
#include <time.h>

int main(int argc, char const *argv[]){
    time_t start_time, end_time;
    double time_diff;
    const int n = 64;
    for(int i = 1; i < n; i++){
        time(&start_time);

        int pre = 0;
        long int res = 1;
        int ope = i;
        while (0 < ope--) {
            res = res + pre;
            pre = res - pre;
        }

        time(&end_time);
        time_diff = difftime(end_time, start_time);
        printf("fib(%d) = %ld, 耗时%fs\n", i, res, time_diff);
    }
}

猜你喜欢

转载自blog.csdn.net/JosephThatwho/article/details/106663490