python--翻譯一段Java程序:已知素數的積,求這2個素數


昨天群里有人貼了下面這張圖片,勾起了大家興趣,引發了大家的討論。

雖然明白求素數的原理,但還沒想明白程序如何寫時,有人貼了如下這段代碼。

因為最近在學 python ,且對其中2個循環的邊界上限為什么這樣寫沒想明白,於是把這個程序翻譯成 python 版。

下面是我的程序:

import time

start = time.clock()


def panduan(n):
    # strn = str(n)
    # if strn[-1] not in ('1', '7', '3', '9'):    # 注1
    #     return False
    for m in range(2, int(n / 2)):    # 注2
        if (n % m == 0):
            return False
    return True

m = m2 = False
i = 707829217
for n in range(3, int(i ** 0.5)):    # 注3
    if (i % n == 0):
        m = panduan(n)
        m2 = panduan(int(i / n))    # 注4
    if (m & m2):
        break

# print(n, int(i / n), sep = '\t')
print('微信號:NY' + str(int(i/n))+str(n))

end = time.clock()
print('耗時:{}'.format(end - start))

 

解析:1)java中“ for(i = 1; i < 10; i++) ”這樣的循環,python中通過“ for i in range(10) ”來變相的實現。

    但java中,邊界上限可以是浮點數等非整數;而range函數中,參數必須是整數。

    所以,2個循環中,向range函數傳值時,使用int函數將計算值強制轉換為整數。

   2)注2,一開始並不明白,為什么要“n/2”,而不直接使用n。

    現在認為,這是為了效率優化。因為m作為n的除數,如果n不是質數,那么在“n/2”范圍內一定能找到可以整除n的數。

   3)注3,原文中,這里的邊界上限使用的是“i/3”,這也是一開始讓我感到困惑的地方,同樣不明白為什么不使用i,並且i的1/3又是如何得來的?

    現在看來,也是效率優化。因為題目中很明確的提示了兩個乘數有大小,所以這2個數肯定不會大於i的1/2。

    至於進一步取到1/3,可能就定的比較隨意了,至少原作者認為較小數在1/3內一定出現。或許有更明確的原因,但我還沒想明白。

    想明白這一點后,既然i是乘積,那么在i的開方中,一定能找到這個較小數。

    所以我把上限改為了i的開方。點擊這里,可以看python中開方的3種寫法

   4)注1,原文中沒有這個判斷。分析數值“707829217”,因為個位數為7,所以2個乘數的個位數一定是7和1、或3和9(感謝 @メ﹎僋翫 指出原代碼中的一個疏漏)。

    因此為了提升效率,增加了一個傳入值n的個位數是否為1或7、3、9的判斷,如果不是直接結束本次函數調用。

    (因為 注4 的修改,導致 注1 的修改提升的效率不大,新版本中注釋掉了這段代碼。)

    需要注意的是,python中“i/n”是一個浮點數(即使 i 可以被 n 整除)。

    所以開始增加注1的判斷后,因為得到的2個數是非質數,追查發現因為傳入值n是浮點數,所以導致該判斷未實現預期效果。

    解決方法,在傳入函數前,先將“i/n”強制轉換成整數。

    同樣道理,在最后的輸出2個質素時,給“i/n”增加int轉化,也是因為不轉換的話,輸出是浮點數。

     5)注4,原文中該行代碼不在 if語句 中,相當於每次for循環都要執行。

     但只有在“i/n”是整數的情況下,判斷該數是否素數才有有意義,所以放入 if語句(即 i 能被 n 整除時) 中更合適。

   6)因為好奇,注1的優化增加后,雖然能感到和原程序比,效率上提高了很多,但是不知道提高了多少,所以對程序又做了改造。

              通過 time.clock() 在程序開始和結束時各獲取一次時間,然后對2者求差,已得到每次的程序運行時間。

      幾種求程序運行時間的方法,請參考這里

     a)按原文翻譯后,程序耗時 28.7040 秒左右;

     b)在此基礎上,增加 注1 的判斷,耗時縮短為 12.7571 秒左右;

     c)這時,做 注4 的修改,並暫時注釋掉 注1,奇跡發生了!耗時在 0.0133秒 左右波動(大多落在 0.013~0.016 范圍內);

      在 注1 被注釋的情況下,這里傳參數值時,不轉換成 int 型也可以,但觀察耗時平均會多 0.001 秒。

      原因不是很理解,可能和 int 、float型 的存儲機制有關。

     d)那么,這時 注1 還能提升效率嗎?恢復后,雖然有一次耗時能達到 0.0126秒 ,但多數時間和(c)項比,時間上並沒有更優。

      所以最終版本,注1 被注釋掉了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM