溢出与概率——斐波那契(不用大数的做法)

此题唯一特色就是数特别大,斐波那契数列的第十万项的值超过longlong可存储的最大范围.
用字符串读取.转为数字发生溢出,高位上的数自动被去除,无法读到完整数,读到的是f(一个不完整的最多20位的longlong形整数)。
 然后从斐波那契第一项开始计算第二项,第三项……第i项(第i项同样溢出,一个不完整的最多20位的longlong型整数),每次把第i项这个溢出数和f这个溢出数进行比较,它们由于都是20位左右的数,比如正常不溢出f=1234,溢出后为234;比如正常不溢出,第i项算出来是1234,溢出会去除高项,变为234;而11234,溢出同样变为234,那么为什么f和第i项(实际上溢出了)相等,就能确定原本的f和第i项(不溢出的原本状态)相等呢?这是因为,f和第i项都是longlong型整数,它们最多可达20位,即使溢出,只要后20位相等,那么原本不溢出的数不相等的概率是很低的。
 这是为什么呢?因为不是所有数都可以成为斐波那契数,斐波那契数的取得尤其特殊的取得方式(是前两项相加不断推出来的),现在某个大数,问他是斐波那契数的第几项,而通过计算到第i项,我们发现第i项这个大数(溢出被削为20位)和输入的那个大数是相等的(20位嘛),如果这样两个数都不等,也就意味着斐波那契还存在某个更大的数,它的后20位和这个输入的大数的后二十位一样,然而斐波那契函数有奇特的构造方式,那么产生这样的更大的数的概率就更低了。几乎可以忽略这种可能性。
#include <stdio.h>
#include<string.h>
#define maxn 100001
char s[maxn];
unsigned long long fn = 0;
unsigned long long f1 = 1;
unsigned long long f2 = 2;
unsigned long long f = 0;

int main()
{
    while(scanf("%s",s)!=EOF)
    {
        int i;
        fn = 0;
        f1 = 1;
        f2 = 2;

        for(i = 0; s[i]!='\0'; i++)
            fn = fn*10 + s[i]-'0';//把字符串转化为数字,过程中发生溢出
        if(fn==1)
            printf("1\n");
        else if(fn==2)
            printf("2\n");
        else
        {
            for(i = 3; i < maxn; i++)//从斐波那切的第一位开始往后算,i就是所求的项数。
            {
                f = f1+f2;
                f1 = f2;
                f2 = f;//f在计算过程中发生溢出
                if(f==fn)//f和fn(字符串转为数字的那个数),两者都发生了溢出,但竟然可以比较是否相等,原因如最上方
                break;
            }
            printf("%d\n",i);
        }
 }
 return 0;
}



猜你喜欢

转载自blog.csdn.net/pipitongkw1/article/details/79250251