2015-10-12 21 views
2

首先,我必須對我的壞英語表示歉意,但我會盡我所能。遞歸和異常的速度比較 - Python

我有一個關於使用python遞歸和異常計算階乘比較速度的練習。

我寫了代碼:

class MyException(Exception): 
    def __init__(self, value): 
     self.value = value 

def standardFactorial(n): 
    if n == 1: 
     return 1 
    return n * standardFactorial(n-1) 

def factorialWithExceptions(n): 
    if n == 1: 
     raise MyException(1) 
    try: 
     factorialWithExceptions(n-1) 
    except MyException as x: 
     raise MyException(n * x.value) 

運行10 000次,300的階乘我得到了類似的結果:

recursion 
1.233912572992267 
exceptions 
9.093736120994436 

有人能向我解釋爲什麼差別這麼大? python中的異常太慢了嗎?或者是什麼問題?構建異常堆棧? 感謝您的回覆。

+0

在第二個例子中,你使用遞歸和異常。 –

回答

0

例外情況應該是針對「特殊」情況。 Python的實現應該比Java更輕,這導致Pythonic方法更傾向於比Java更頻繁地使用異常(有一個座右銘:最好是要求寬恕而不是允許)。即便如此,在幾乎所有的語言中都使用異常來控制流量,因爲它使得代碼的推理更加困難,並且還因爲創建異常,捕獲異常,展開所有位並繼續。因爲只是爲了比較,我測試了java的等價物(使用BigInteger's,因爲只是使用ints導致因子(300)的無意義結果。第一次,我得到了非常奇怪的結果,我將會有來看看,但在更新代碼在同一個應用程序做兩件事,做一些檢查,確保希望我們不要因優化等:

import java.math.BigInteger; 


class BigIntegerHolder extends Exception 
{ 
    public BigInteger bigInt; 
    public BigIntegerHolder(BigInteger x) { this.bigInt = x; } 
} 

class Factorial 
{ 

    public static BigInteger fact(int n) 
    { 
     if (n == 1) 
      { 
       return BigInteger.valueOf(1); 
      } 
     return fact(n-1).multiply(BigInteger.valueOf(n)); 
    } 



    public static void factExcept(int n) throws BigIntegerHolder 
    { 
     if (n == 1) 
      { 
       throw new BigIntegerHolder(BigInteger.valueOf(1)); 
      } 
     try { 
      factExcept(n-1); 
     } 
     catch (BigIntegerHolder ex) 
      { 
       throw new BigIntegerHolder(ex.bigInt.multiply(BigInteger.valueOf(n))); 
      } 
    } 


    public static void main(String args[]) 
    { 
     BigInteger realValue = fact(300); 
     int count = 0; 

     long start = System.currentTimeMillis(); 
     for (int i = 0; i < 10000; i++) 
      { 
       try { 
       factExcept(300); 
       } 
       catch (BigIntegerHolder ex) 
        { 
         if (realValue.equals(ex.bigInt)) 
          { 
           count += 1; 
          } 
        } 

      } 
     long end = System.currentTimeMillis(); 
     System.out.println("We got it right " + count + " times in " + (end - start) + " ms"); 


     count = 0; 
     start = System.currentTimeMillis(); 
     for (int j = 0; j < 10000; j++) 
      { 
       BigInteger x = fact(300); 
       if (realValue.equals(x)) 
        { 
         count += 1; 
        } 
      } 
     end = System.currentTimeMillis(); 
     System.out.println("We got it right " + count + " times in " + (end - start) + " ms"); 

    } 
} 

這種產出假結果:

我們在23708 ms得到了正確的10000次ms

我們這樣做是正確10000次在271毫秒

(表明在Java中,有例外做它幾乎是100倍慢)