2013-03-14 56 views
2

在我的課程中,我們被分配了一個問題來創建一個「factorizer」應用程序,它可以計算任何數字的素數因子分解,直到一個非常大的數字。他給了我們一個Number.java類,它可以計算出數字是否爲素數或不是明顯的用途。有用或浪費內存?

// Number.java 
public class Number { 
    long n; 
    public Number(long number) { 
     n = number; 
    } 
    boolean isPrime() { 
     for(long k = 2; k < n; k++) { 
      if(n % k == 0) return false; 
     } 
     return true; 
    } 
} 

與此唯一的問題是,Number.java類是它有一個構造函數,在我的腦海在這種情況下,不那麼「移動」。我的意思是,在我的循環中計算參數的主要因素,一個新的Number對象被一遍又一遍地創建。在頂部定義一個private Number isPrimeFactor = new Number()而不是爲每個循環的重複創建一個新的Number isPrimeFactor = new Number(i)是否更有意義?我問了我的老師這件事,但他並沒有真正回答。以下是我正在談論的一些示例代碼。

while (remainder!=0 && j<n) { 
     Number isFactor = new Number(j); 
     if(isFactor.isPrime() && remainder%j==0) { 
      remainder = remainder/j; 
      factor[i]=j; 
      temp = (int) j; 
      multiplicity[temp] = multiplicity[temp]+1; 
      i++; 
     } else { 
      j++; 
     } 
    } 
+0

首先,您只需要Number,Integer和Long的特定子集。浮動和雙重沒有意義。順便說一句,爲了檢查數字n是否爲素數,不需要檢查大於n/2的數字是否是除數,因爲給定n,沒有大於n/2的除數。 – m0skit0 2013-03-14 15:25:54

+1

'k'只需要上升到'sqrt(n)',這對於大'n'來說會更快。關於循環和創建對象,讓Java的垃圾收集器處理它。 – 2013-03-14 15:26:03

+0

這聽起來很像過早的優化。看起來你會爲每個數字創建數百或數千個分區,但是他們正在考慮創建初始對象的小開銷。 – msam 2013-03-14 15:31:32

回答

2

是,new是相當昂貴的,這意味着調用幾千次isPrimeFactor = new Number(j)是除具有Number只是一個實例,並用,比如更改相關n值,isPrimeFactor.setN(j)效率較低。這是因爲new分配了新的內存,並且一旦實例無法再到達,垃圾收集器會不時釋放該內存。

儘管讓Number成爲不可變的優點是你不會冒險冒險一塊代碼改變它的值,而另一個代碼認爲它沒有改變(例如,當你使用線程時非常好的屬性) 。

順便說一句,我認爲Number由你的教授給出的類是一個可怕的面向對象設計,可變或不可變。

+0

我同意,他的'數字'類是一個可怕的面向對象設計。 – pattmorter 2013-03-14 15:37:58

+1

只是好奇,你是說它是可怕的OO,因爲它所有的唯一功能是檢查一個數是否爲素數,可能更適合作爲一個簡單的靜態方法?假設一個數字具有附加功能,OO看起來很好。只有改變我會做的是,因爲它是不可變的,所以一旦第一次計算,就會緩存'isPrime()'的結果。並且可能暴露'isPrime()'委託給的'static isPrime(long)'方便的方法。 – Blake 2013-03-14 16:02:16

+1

@Blake,是的,如果您將其他功能添加到'Number'類,那麼它可以成爲一個好設計,只要您按照您的建議緩存'isPrime()'的結果即可。我只是認爲pattmorter給了我們整個班級的定義。 – Fabien 2013-03-14 16:11:55

0

內存/速度/代碼可讀性/維護之間總是有選擇。因此,以客觀的方式回答問題是不可能的。

該解決方案效率低下嗎?也許,但是再一次,函數調用很昂貴,所以任何涉及函數調用的解決方案都可能被標記爲低效。

如果這是家庭作業或學習練習,那麼代碼效率並不是非常重要,但要明確說明所涉及概念的代碼非常重要!

詩篇。

我看到的大多數檢查質數的代碼都有一個方法「isPrime」,它將一個數字/整數作爲參數。

-2

你是對的,在循環內分配對象是一種性能反模式。您可以通過使用靜態類成員來提高執行速度並改善內存使用情況。

// Number.java 
public class Number { 
    private static long n; 
public static void setNumber(long number){ 
     n = number; 
} 
static boolean isPrime() { 
    for(long k = 2; k < n; k++) { 
     if(n % k == 0) return false; 
    } 
    return true; 
} 
} 
+0

我無法理解你的答案......這個問題有什麼靜態的問題? – m0skit0 2013-03-14 15:33:00

+0

@ m0skit0 static表示類和它的對象的單個實例,從而節省內存和靜態方法比對象方法更快訪問 因此,他既節省內存又節省內存 – 2013-03-14 15:51:42

+2

對不起,但我認爲這是一個遠遠大於反模式在循環內分配對象。構造對象的實例,然後在靜態字段中設置該值是非常危險的,完全不是線程安全的,並且非直觀。它在單線程上下文中並不安全 – Blake 2013-03-14 15:53:55

0

拋開其他優化,沒有理由爲這些創建數字,整數等。您可以跳過上述所有與此:

public static boolean isPrime(long number) { 
    for(long k = 2; k < n; k++) { 
     if(n % k == 0) return false; 
    } 
    return true; 
} 
+0

是的,我知道,但我的老師是「真正的程序員」傢伙之一,並希望我們做OOP,而不是在任何情況下程序。我知道面向對象是一種很好的做法,但同樣在這裏浪費,但他並不在乎。 – pattmorter 2013-03-14 15:36:37

0

它肯定會更快地只有一次實例的數量和重複轉讓其領域。但是,在這種情況下,測試isPrime可能是瓶頸,因此您幾乎不會注意到其中的差異。

1

將使這裏什麼意義上具有傳遞nisPrime()的唯一目的構造:這就是函數參數的!

public class PrimeChecker {  
    public static boolean isPrime(long n) { 
    for(long k = 2; k * k < n; k++) { 
     if(n % k == 0) return false; 
    } 
    return true; 
    } 
}