使用Rust语言编写计算fibonacci-sequence的直接计算和矩阵快速幂方法的效率对比

最近开了个新坑,学习Rust,主要是因为自己一直想学一门函数式的语言。首先我们直接用公式法计算斐波那契数列,代码如下:

use std::io;
use num::BigUint;
use num::traits::{Zero,One};

fn main() {
    println!("Calculate Fibonacci sequence please type n \nand then give your n th number of sequence");
    let mut input_str=String::new();
    io::stdin().read_line(&mut input_str).expect("INPUT ERROR");
    let n:u32=input_str.trim().parse().expect("NOT A NUMBER");
    println!("the {} n th number of sequence is\n{}",n,fibonacci_cal(n));
}

fn fibonacci_cal(mut i:u32) -> BigUint
{
    let mut n1:BigUint=Zero::zero();
    let mut n2:BigUint=One::one();
    match i {
        0=> n1,
        1=> n2,
        _=>{
            while i >=2 {
                let k=n2.clone();
                n2+=n1;
                n1=k;
                i-=1;
            }
           n2
        }
    }
}


CSDN居然没有Rust的语法高亮!(原来是有高亮的,找不到标签选没有设置就有高亮)

为了让计算时间较长方便对比我打算计算一个u128类型都装不下的数,所以我是用了num库下的BigUint类型,该类型的实际有效范围只与机器配置相关,然后我们用time命令测一下计算第200001个数的时间,当然输入我们从文件重定向过去。

斐波那契数列的计算过程可以用一个矩阵乘法来表示,而求第一二项后任意一项的过程就是反复乘以该矩阵,我们可以先求该矩阵的n次幂,然后再用第一二项乘以该矩阵,然后求幂的时候我们可以用快速幂算法,该算法在网上有大量论述,我在这里就直接贴代码了。

use std::io;
use num::BigUint;
use num::traits::{Zero,One};

fn main() {
    println!("Calculate Fibonacci sequence please type n \nand then give your n th number of sequence");
    let mut input_str=String::new();
    io::stdin().read_line(&mut input_str).expect("INPUT ERROR");
    let n:u32=input_str.trim().parse().expect("NOT A NUMBER");
    println!("the {} n th number of sequence is\n{}",n,fibonacci_cal(n));
    // let mx1=[BigUint::from(1u32),BigUint::from(1u32),BigUint::from(1u32),BigUint::from(2u32)];
    // let mx2=mx1.clone();
    // let mx3=matrix_multi(mx1,mx2);
    // println!("the arr is {} {} {} {}",mx3[0],mx3[1],mx3[2],mx3[3]);
}

fn fibonacci_cal(i:u32) -> BigUint
{
    let n1:BigUint=Zero::zero();
    let n2:BigUint=One::one();
    match i {
        0=> n1,
        1=> n2,
        _=>{
            let p=i/2;
            let t=i%2;
            let mx=[BigUint::from(1u32),BigUint::from(1u32),BigUint::from(1u32),BigUint::from(2u32)];
            let rel_ma=matrix_fast_pow(mx,p);
            let n2=if t==0 { n1*&rel_ma[0]+n2*&rel_ma[2] } else { n1*&rel_ma[1]+n2*&rel_ma[3] };
           n2
        }
    }
}
//4*4 matrix 0 1 0 1
//           2 3 2 3
fn matrix_multi(m1:&[BigUint;4],m2:&[BigUint;4])->[BigUint;4]
{
    // let mut rel_matrix=[Zero::zero(),Zero::zero(),Zero::zero(),Zero::zero()];
    let mut rel_matrix:[BigUint;4]=Default::default();
    rel_matrix[0]=&m1[0]*&m2[0]+&m1[1]*&m2[2];
    rel_matrix[1]=&m1[0]*&m2[1]+&m1[1]*&m2[3];
    rel_matrix[2]=&m1[2]*&m2[0]+&m1[3]*&m2[2];
    rel_matrix[3]=&m1[2]*&m2[1]+&m1[3]*&m2[3];
    rel_matrix
}

fn matrix_fast_pow(mut m:[BigUint;4],n:u32)->[BigUint;4]
{
    let mut rel_mx=[BigUint::from(1u32),BigUint::from(0u32),BigUint::from(0u32),BigUint::from(1u32)];
    let mut bi=1 as u32;
    loop {
        if n&bi!=0 { rel_mx=matrix_multi(&rel_mx,&m);}
        m=matrix_multi(&m,&m);
        bi=bi<<1;
        if bi>n {break;}
        else if bi==1u32<<31 {rel_mx=matrix_multi(&rel_mx,&m);break;}
    }
    rel_mx
}

  7s多变1s这就是算法的力量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值