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

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

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

    莊周夢蝶

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

    可笑的優(yōu)化

    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?


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

    #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分鐘,太讓人難以接受了。那么是否能優(yōu)化下?怎么優(yōu)化?我的機器是雙核的,跑這個單進程單線程的程序只利用了一半的CPU,那么能不能搞成兩個線程來計算?緩存需要在兩個線程之間做同步,顯然讀的多,寫的少,應(yīng)該采用讀寫鎖。OK,第二個版本利用ACE的線程封裝實現(xiàn)如下:
    #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 ();
    }
       
        將數(shù)據(jù)分成了兩半,利用兩個線程來計算,果然快了一點,快了多少呢?從13分鐘減少到9分鐘,CPU利用率也到了100%,內(nèi)存占用也降低了一半,似乎成績不錯呀。正在沾沾自喜之際,突然想起,能不能簡單地暴力破解,咱不搞緩存,不搞多線程,看看效果怎么樣。那么第三個版本簡單實現(xiàn)如下:
    #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;
    }

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

         總結(jié)教訓(xùn),想當(dāng)然的性能估計是愚不可及的,想當(dāng)然的優(yōu)化是愚不可及的,簡單直接才是美!


    評論

    # re: 可笑的優(yōu)化  回復(fù)  更多評論   

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

    # re: 可笑的優(yōu)化  回復(fù)  更多評論   

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

    你確定不是因為循環(huán)次數(shù)不同的原因?

    # re: 可笑的優(yōu)化  回復(fù)  更多評論   

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

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产精品亚洲综合| 亚洲女初尝黑人巨高清| 亚洲av伊人久久综合密臀性色 | 亚洲av无码国产精品夜色午夜 | 一级毛片直播亚洲| 亚洲精品无码高潮喷水A片软| **毛片免费观看久久精品| 亚洲欧洲国产日韩精品| 无码人妻精品中文字幕免费 | 亚洲中文字幕视频国产| 无码免费又爽又高潮喷水的视频 | 亚洲综合精品香蕉久久网97| 久久免费观看国产99精品| 久久亚洲国产午夜精品理论片| 久久久久久久久久免免费精品 | 亚洲人成77777在线播放网站| 免费视频成人国产精品网站| 在线观看免费人成视频| 亚洲第一网站免费视频| 免费看h片的网站| 国产精品亚洲综合久久| 日本人的色道www免费一区| 国产成人精品久久亚洲高清不卡| 免费在线黄色网址| 久久WWW免费人成—看片| 亚洲乱码卡三乱码新区| 国产成人免费网站在线观看| 国产JIZZ中国JIZZ免费看| 亚洲AV无码码潮喷在线观看 | 性感美女视频在线观看免费精品| 亚洲熟妇无码八V在线播放| 免费一级成人毛片| 老司机在线免费视频| 黄网站色视频免费看无下截 | 亚洲精品成人久久| 国产亚洲精品久久久久秋霞| 99久久国产免费中文无字幕| 亚洲色偷偷偷综合网| 亚洲第一香蕉视频| 亚洲AV无码精品色午夜果冻不卡| 亚洲人成色77777在线观看大|