在Fibonacci序列中找到第n个项的最后几位的问题

时间:2015-07-22 13:19:19

标签: c fibonacci modulus

我使用在这个问题的接受答案中给出的好的博客文章写了一些代码来确定第n个Fibonacci数:Finding out nth fibonacci number for very large 'n'。我这样做是为了练习在projecteuler上给出的更难的递归问题,但这并不是真正相关的。该方法依赖于将问题转换为形式

的小线性代数问题

Fn = T ^ n F1

其中F1 =(1 1)^ t且Fn包含第n和第(n-1)个斐波纳契数。然后可以在O(log n)时间内确定项T ^ n。我成功地实现了它,它似乎工作正常。当我执行矩阵求幂时,我使用%10000,所以我只得到最后4位数,这似乎有效(我检查了一些大的斐波纳契数)。但是,我想通过增加数字10000来尝试获得更多的最后数字。但这似乎不起作用。我不再得到正确的答案。这是我的代码

#include<stdio.h>
#include<math.h>
#include<stdlib.h>

const unsigned long M = 10000;

unsigned long int * matProd(unsigned long int * A, unsigned long int * B){
  unsigned long int * C;
  C = malloc(4*sizeof(unsigned long int));
  C[0] = ((A[0]*B[0]%M) + (A[1]*B[2]%M)) % M;
  C[1] = ((A[0]*B[1]%M) + (A[1]*B[3]%M)) % M;
  C[2] = ((A[2]*B[0]%M) + (A[3]*B[2]%M)) % M;
  C[3] = ((A[2]*B[1]%M) + (A[3]*B[3]%M)) % M;
  return C;
}

unsigned long int * matExp(unsigned long int *A, unsigned long int n){
  if (n==1){
    return A;
  }
  if (n%2==0){
    return matExp(matProd(A,A),n/2);
  }
  return matProd(A,matExp(A,n-1));
}

unsigned long int findFib(unsigned long int n){
  unsigned long int A[4] = {0, 1, 1, 1};
  unsigned long int * C;
  C = malloc(4*sizeof(unsigned long int));
  C = matExp(A,n-2);
  return (C[2]+C[3]);
}

main(){
  unsigned long int n = 300;
  printf("%ld\n",findFib(n));
}

关于正确的编码约定和可以改进的事情,可能存在几个问题。我认为改为long int可能会解决问题,但这似乎没有办法解决问题。所以基本上问题是将M增加到例如1000000不会给我更多的数字,而是让我胡说八道。我犯了什么错误?

P.S。抱歉数学格式不佳,我习惯于math.stackexchange。

2 个答案:

答案 0 :(得分:1)

问题可能是您在long大小为32位的系统上运行,我认为是Windows的情况。您可以通过编译并运行printf("%d\n", sizeof(long))来检查这一点,4应输出M=1000000=10^6

由于使用M,两个小于10^12的数字的乘积可以达到unsigned long,因此在计算矩阵条目时会出现溢出问题2^32-1最多可以保留4 * 10^9或大约unsigned long long

要解决此问题,只需使用unsigned long代替uint64_t。或者更好的是,#include <stdint.h>,在所有平台上保证为64位(并且需要M)。这应该使您的代码适用于sqrt(2^64)~10^9最多package com.xxproj; /** * Bu sınıf bir aracı temsil etmektedir. * @author Bahadır Yılmaz * @version 1.0.0 * @since 1.0.0 */ public class Car { private String make; private int year; private int mileage; /** * Car sınıfının temel tanımlamalarını yapar. * @param make Aracın üretici firması * @param year Aracın üretim yılı * @param mileage Aracın yaptığı mesafe * @since 1.0.0 */ public Car(String make, int year, int mileage) { this.make = make; this.year = year; this.mileage = mileage; } /** * Aracı hareket ettirir. * @param miles Aracın hareket edeceği mesafe * @since 1.0.0 */ public void drive(int miles) { if(miles > 0) mileage += miles; } /** * Aracın yaptığı toplam mesafe bilgisini verir. * @return milage Aracın yaptığı toplam mesafe */ public int getMileage() { return mileage; } /** * Aracın üretici firma bilgisini verir. * @return make Aracın üretici firması */ public String getMake() { return make; } /** * Aracın üretim yılı bilgisini verir. * @return year Aracın üretim yılı */ public int getYear() { return year; } } 。如果你需要大于那个,你需要使用一个大整数库。

答案 1 :(得分:1)

如果该程序适用于M == 10000M == 1000000(或M == 100000}失败,那么这可能意味着您的C实现的unsigned long int类型为32位宽。

如果您的矩阵元素仅从Z 10000 绘制,则它们最多需要14个有效二进制数字。在减少模M之前,在矩阵乘法函数中计算的乘积可能因此需要最多28个二进制数字。但是,如果将M增加到100000,则矩阵元素最多需要17个二进制数字,中间产品最多需要34个。减少模M为时已晚,无法防止溢出32位整数,因此给你垃圾结果。

您可以考虑将元素类型声明为uint64_t。如果这是一个溢出问题,那么应该给你足够的额外数字来处理M == 1000000