<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    可笑的優化

    Posted on 2009-01-23 00:08 dennis 閱讀(617) 評論(3)  編輯  收藏
        這幾天沒事做的時候都會上projecteuler.net上面去做題,其中14題是這樣的:
    he following iterative sequence is defined for the set of positive integers:

    n → n/2 (n is even)
    n → 3n + 1 (n is odd)

    Using the rule above and starting with 13, we generate the following sequence:

    13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

    It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.

    Which starting number, under one million, produces the longest chain?


        題目并不難理解,這個據說是著名的角谷猜想,現在要找到100萬以下的數字中展開這個鏈最長的數字是多少。如果我一開始就直接按照題意來解答,這個題目花不了幾分鐘,直接暴力法。然而我卻想的太多了,我猜想在計算這個鏈條長度的過程中會不會有很多數字會重復計算,如果加上緩存以前計算的結果是否能節約比較多的時間?那么第一次解答如下:

    #include<iostream>
    #include
    <map>
    #include
    <windows.h>
    using namespace std;
    unsigned 
    long produce_term(unsigned long n)
    {
        
    if(n&1)
            
    return 3*n+1;
        
    else
            
    return n>>1;
    }
    int main()
    {
        map
    <unsigned long,int> counters;
        
    int max_i=0;
        
    int max_count=0;
        DWORD tick1,tickPassed;
        tick1 
    = GetTickCount(); 
        
    for(int i=1;i<1000000;i++)
        {
            
    int sum=2;
            unsigned 
    long term=i;
            
    while((term=produce_term(term))!=1)
            {
                
    if(counters[term]){
                    sum
    +=counters[term];
                    
    break;
                }
    else
                    sum
    +=1;
            }

            
    if(sum>max_count)
            {
                max_i
    =i;
                max_count
    =sum;
                counters[i]
    =sum;
            }

        }
        tickPassed 
    = GetTickCount()-tick1; 
        cout
    <<tickPassed<<endl;
        cout
    <<max_i<<endl<<max_count<<endl;
        
    return 0;
    }
      
        遺憾的是,這個版本跑了快13分鐘,太讓人難以接受了。那么是否能優化下?怎么優化?我的機器是雙核的,跑這個單進程單線程的程序只利用了一半的CPU,那么能不能搞成兩個線程來計算?緩存需要在兩個線程之間做同步,顯然讀的多,寫的少,應該采用讀寫鎖。OK,第二個版本利用ACE的線程封裝實現如下:
    #include<iostream>
    #include
    <map>
    #include 
    "ace/Thread_mutex.h"
    #include 
    "ace/Synch.h"
    #include 
    "ace/Thread_Manager.h"
    using namespace std;
    class ThreadSafeMap
    {
    public:
        ThreadSafeMap()
        {
        }
        
    int get(unsigned long n)
        {
            ACE_READ_GUARD_RETURN(ACE_RW_Thread_Mutex,guard,mutex_,
    0);
            
    return counters_[n];
        }
        
    int put(unsigned long key,int value)
        {
            ACE_WRITE_GUARD_RETURN(ACE_RW_Thread_Mutex,guard,mutex_,
    -1);
            counters_[key]
    =value;
            
    return 0;
        }

    private:
        map
    <unsigned long,int> counters_;
        ACE_RW_Thread_Mutex mutex_;
    };
    unsigned 
    long produce_term(unsigned long n)
    {
        
    if(n&1)
            
    return 3*n+1;
        
    else
            
    return n>>1;
    }
    static ThreadSafeMap counters;
    ACE_THR_FUNC_RETURN run_svc (
    void *arg)
    {
        
    int max_i=0;
        
    int max_count=0;
        
    for(int i=500001;i<1000000;i++)
        {
            
    int sum=2;
            unsigned 
    long term=i;
            
    while((term=produce_term(term))!=1)
            {
                
    if(counters.get(term)){
                    sum
    +=counters.get(term);
                    
    break;
                }
    else
                    sum
    +=1;
            }

            
    if(sum>max_count)
            {
                max_i
    =i;
                max_count
    =sum;
                counters.put(i,sum);
            }

        }
        cout
    <<max_i<<endl<<max_count<<endl;
        
    return 0;
    }
    int main(int ac,char* argv[])
    {
        
    if (ACE_Thread_Manager::instance ()->spawn (
            
    // Pointer to function entry point.
            run_svc,
            
    // <run_svc> parameter.
            NULL,
            THR_DETACHED 
    | THR_SCOPE_SYSTEM) == -1)
            
    return -1;
        
    int max_i=0;
        
    int max_count=0;

        
    for(int i=1;i<500000;i++)
        {
            
    int sum=2;
            unsigned 
    long term=i;
            
    while((term=produce_term(term))!=1)
            {
                
    if(counters.get(term)){
                    sum
    +=counters.get(term);
                    
    break;
                }
    else
                    sum
    +=1;
            }

            
    if(sum>max_count)
            {
                max_i
    =i;
                max_count
    =sum;
                counters.put(i,sum);
            }

        }
        cout
    <<max_i<<endl<<max_count<<endl;
        
    return ACE_Thread_Manager::instance ()->wait ();
    }
       
        將數據分成了兩半,利用兩個線程來計算,果然快了一點,快了多少呢?從13分鐘減少到9分鐘,CPU利用率也到了100%,內存占用也降低了一半,似乎成績不錯呀。正在沾沾自喜之際,突然想起,能不能簡單地暴力破解,咱不搞緩存,不搞多線程,看看效果怎么樣。那么第三個版本簡單實現如下:
    #include<iostream>
    using namespace std;
    unsigned 
    long produce_term(unsigned long n)
    {
        
    if(n&1)
            
    return 3*n+1;
        
    else
            
    return n>>1;
    }
    int main()
    {
      
    int max_i;
      
    int max_count=0;
      
    for(int i=1;i<1000000;i++)
      {
         
    int count=2;
         unsigned 
    long term=i;
         
    while((term=produce_term(term))>1)
             count
    +=1;
         
    if(count>max_count){
               max_i
    =i;
               max_count
    =count;
         }
      }
      cout
    <<max_i<<endl<<max_count<<endl;
      system(
    "pause");
      
    return 0;
    }

        程序執行的結果讓我驚掉了下巴,竟然只執行了1秒多,換成java也是一樣。什么緩存、多線程,全拋到了九霄云外。

         總結教訓,想當然的性能估計是愚不可及的,想當然的優化是愚不可及的,簡單直接才是美!


    評論

    # re: 可笑的優化  回復  更多評論   

    2009-01-23 01:20 by jtuki
    想當然的性能估計是愚不可及的,想當然的優化是愚不可及的,簡單直接才是美!
    -----------------
    確實如此.. -_-
    如果緩存了前面計算的結果, 理論上應該要快一些, 不過對內存的操作貌似太恐怖了.. 100萬.. 而且還是每次都要 if else 的定位和比較..
    俺在考慮要不使用 C 實現試一試? 看看速度會不會稍微快一點? 譬如 7分鐘? :D

    # re: 可笑的優化  回復  更多評論   

    2009-01-23 12:34 by 司馬崖余
    for(int i=13;i<14;i++){

    你確定不是因為循環次數不同的原因?

    # re: 可笑的優化  回復  更多評論   

    2009-01-23 14:21 by dennis
    @司馬崖余
    我確定,文章中的代碼是拷貝錯了,改了

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲成a人片在线看| 亚洲色成人网一二三区| 亚洲av乱码一区二区三区按摩| 精品熟女少妇av免费久久| 亚洲尹人九九大色香蕉网站| 午夜免费福利视频| 91亚洲国产成人精品下载| 4399影视免费观看高清直播| 亚洲成年人电影网站| 久久久久国色AV免费看图片| 亚洲国产欧美日韩精品一区二区三区| 动漫黄网站免费永久在线观看| 亚洲色偷偷综合亚洲av78 | 午夜精品免费在线观看 | 亚洲人成77777在线播放网站不卡| 91久久青青草原线免费| 国产精品亚洲自在线播放页码| 免费羞羞视频网站| 色吊丝性永久免费看码| 国产亚洲真人做受在线观看| 久久青草免费91线频观看站街| 亚洲日本乱码一区二区在线二产线| 欧美日韩国产免费一区二区三区| 亚洲国产欧美国产综合一区 | 亚洲av永久无码精品网站| 30岁的女人韩剧免费观看| 亚洲精品久久久久无码AV片软件| 免费一级大黄特色大片| 青青青国产手机频在线免费观看| 亚洲六月丁香六月婷婷色伊人| 国产高清视频在线免费观看| ww在线观视频免费观看w| 亚洲美女一区二区三区| 日韩人妻无码免费视频一区二区三区| 九九综合VA免费看| 亚洲综合色丁香麻豆| 亚洲成AⅤ人影院在线观看| 久久99热精品免费观看牛牛| 亚洲AV成人无码网天堂| 亚洲Av永久无码精品三区在线 | 野花高清在线观看免费完整版中文 |