zoukankan      html  css  js  c++  java
  • Fibonacci各种玩法

    1-基础入门玩法

    auto fib(auto n){
        if (n == 0)  return 0;
        if (n == 1) return 1;
        return fib(n-1) + fib(n-2);
    }

    2-metaprogramming,编译期间展开

    template<auto N>
    struct FibT;
    
    template<>
    struct FibT<0>{
        static constexpr int result = 0;
    };
    
    template<>
    struct FibT<1>{
        static constexpr int result = 1;
    };
    
    template<auto N>
    struct FibT{
        static constexpr int result = FibT<N-1>::result + FibT<N-2>::result;
    };
    template<auto N>
    inline constexpr auto fib_v = FibT<N>::result;
    std::cout << fib_v<3> << std::endl;

    3,metaprogramming,同样编译期间计算展开

    template<auto N>
    struct FibT{
        static auto constexpr compute(){
            auto result = 0;
            if constexpr (N==0) result = 0;
            else if constexpr (N==1) result = 1;
            else
                result = FibT<N-1>::compute() + FibT<N-2>::compute();
            return result;
        }
    };
    template<auto N>
    inline constexpr auto fib_v = FibT<N>::compute();
    std::cout << fib_v<3> << std::endl;

    4,运行期间展开的有个问题,由于是递归,会再递归的 node上重复计算

    比如fib(5),第一次递归,fib(4),fib(3),而计算fib(4)也计算了fib(3)

    #include <iostream>
    #include <vector>
    
    static std::vector<int > cache{0,1};
    
    auto fib(auto n){
        if(cache.size() > n){
            return cache[n];
        }
        else{
            auto var = fib(n-1) + fib(n-2);
            cache.emplace_back(var);
            return var;
    
        }
    }
    
    
    int main() {
        std::cout << fib(5) << std::endl;
        std::cout << fib(4) << std::endl;// cached
    
        std::cout << "container:" << std::endl;
        for(auto &&v : cache){
            std::cout << v << "   " ;
        }
        std::cout << std::endl;
        return 0;
    }

     输出:

    5
    3
    container:
    0   1   1   2   3   5   

    5,对任意函数的结果cache

    template<typename ResultT, typename ... Args>
    auto make_memoized(ResultT (*func)(Args...))
    {
        using TupleArgsT = std::tuple< Args...>;
        std::map< TupleArgsT, ResultT> cache;// unordered map can not use in this place
    
        return [func, cache](Args... args) mutable -> ResultT
        {
            auto args_tuple= std::make_tuple( args...);
            auto iter = cache.find(args_tuple);
            if(iter == cache.end()){
                auto result = func( args...);
                cache[args_tuple] = result;
                return result;
            }
            else{
                return cache[args_tuple];
            }
            return ResultT();
        };
    }

    调用方法:

    auto fib_mem = make_memoized(fib);
    fib_mem(fib_n);
    fib_mem(fib_n) ;
    fib_mem(fib_n) ;

    第一次会慢点,但是第二次调用会非常快,但是这个也有缺陷,

    --- 函数结果被cache,函数本身的过程没cache

    --- 适合调用相同的函数多次

     对 N=40 性能的测试:

    #include <iostream>
    #include <unordered_map>
    #include <tuple>
    #include <functional>
    #include <map>
    #include <chrono>
    
    class Timer{
    private:
        std::chrono::steady_clock::time_point last;
    public:
        Timer(): last{std::chrono::steady_clock::now()}{
    
        }
        void reset(){
            last = std::chrono::steady_clock::now();
        }
        void printDiff(const std::string &msg = "time diff: "){
            auto now{std::chrono::steady_clock::now()};
            std::chrono::duration<double, std::milli> diff{now-last};
            std::cout << msg << diff.count() << std::endl;
            last = std::chrono::steady_clock::now();
        }
    };
    
    
    
    int fib(int n){
        if(n==0 || n==1) return n;
        else
            return fib(n-1)+fib(n-2);
    }
    
    
    template<typename ResultT, typename ... Args>
    auto make_memoized(ResultT (*func)(Args...))
    {
        using TupleArgsT = std::tuple< Args...>;
        std::map< TupleArgsT, ResultT> cache;// unordered map can not use in this place
    
        return [func, cache](Args... args) mutable -> ResultT
        {
            auto args_tuple= std::make_tuple( args...);
    
            auto iter = cache.find(args_tuple);
    
            if(iter == cache.end()){
                auto result = func( args...);
                cache[args_tuple] = result;
                return result;
            }
            else{
                return cache[args_tuple];
            }
            return ResultT();
        };
    }
    
    
    
    template<auto N>
    struct FibT;
    
    template<>
    struct FibT<0>{
        static constexpr int result = 0;
    };
    
    template<>
    struct FibT<1>{
        static constexpr int result = 1;
    };
    
    template<auto N>
    struct FibT{
        static constexpr int result = FibT<N-1>::result + FibT<N-2>::result;
    };
    template<auto N>
    inline constexpr auto fib_v = FibT<N>::result;
    
    
    
    int main() {
        constexpr auto fib_n = 40;
        Timer t;
        fib(fib_n) ;
        fib(fib_n) ;
        fib(fib_n) ;
        t.printDiff("fib() time:   ");
        t.reset();
    
        auto fib_mem = make_memoized(fib);
        fib_mem(fib_n);
        fib_mem(fib_n) ;
        fib_mem(fib_n) ;
        t.printDiff("fib_mem() time:   ");
        t.reset();
    
        fib_v<fib_n>;
        fib_v<fib_n>;
        fib_v<fib_n>;
        t.printDiff("metaprogramming time:    ");
        t.reset();
    
        
        return 0;
    }
    View Code

    上面代码是对每种函数调用3次结果:

    fib() time: 3202.85
    fib_mem() time: 1066.87
    metaprogramming time: 0.000604

    如果调用一次:

    fib() time: 1056.4
    fib_mem() time: 1056.15
    metaprogramming time: 0.000681

    编译器的递归也有限制,比如将fib_n = 100时候:

    Scanning dependencies of target fib_mem
    [ 50%] Building CXX object CMakeFiles/fib_mem.dir/main.cpp.o
    /home/father/dev/cpp/fib_mem/main.cpp: In instantiation of ‘constexpr const int FibT<47>::result’:
    /home/father/dev/cpp/fib_mem/main.cpp:76:46:   recursively required from ‘constexpr const int FibT<99>::result’
    /home/father/dev/cpp/fib_mem/main.cpp:76:46:   required from ‘constexpr const int FibT<100>::result’
    /home/father/dev/cpp/fib_mem/main.cpp:79:40:   required from ‘constexpr const auto fib_v<100>/home/father/dev/cpp/fib_mem/main.cpp:101:5:   required from here
    /home/father/dev/cpp/fib_mem/main.cpp:76:53: warning: integer overflow in expression of type ‘int’ results in ‘-1323752223’ [-Woverflow]
       76 |     static constexpr int result = FibT<N-1>::result + FibT<N-2>::result;
          |                                              ~~~~~~~^~~~~~~~~~~~~~~~~~~
    /home/father/dev/cpp/fib_mem/main.cpp:76:26: error: overflow in constant expression [-fpermissive]
       76 |     static constexpr int result = FibT<N-1>::result + FibT<N-2>::result;
          |                          ^~~~~~
    /home/father/dev/cpp/fib_mem/main.cpp:76:26: error: overflow in constant expression [-fpermissive]
    make[2]: *** [CMakeFiles/fib_mem.dir/build.make:72: CMakeFiles/fib_mem.dir/main.cpp.o] Error 1
    make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/fib_mem.dir/all] Error 2
    make: *** [Makefile:91: all] Error 2

    REF:

    Functional Programming In C++ --- Ivan

  • 相关阅读:
    学习tornado:介绍
    【Unity Shaders】Using Textures for Effects介绍
    高性能C++网络库libtnet实现:http
    理解WebKit和Chromium: 硬件加速之RenderLayer树到合成树
    【Unity Shaders】Diffuse Shading——使用2D ramp texture来创建一个假的BRDF(双向反射分布函数)
    【Unity Shaders】Diffuse Shading——漫反射光照改善技巧
    ③ 设计模式的艺术-16.访问者(Visitor)模式艺术
    ② 设计模式的艺术-15.观察者(Observer)模式
    ① 设计模式的艺术-14.职责链(Chain of Responsibility)模式
    ⑦ 设计模式的艺术-13.代理(Proxy)模式
  • 原文地址:https://www.cnblogs.com/gearslogy/p/15160801.html
Copyright © 2011-2022 走看看