簡體   English   中英

用於大輸入的Java優化算術和賦值運算符

[英]Java Optimizing arithmetic and Assignment Operators for large input

我有一段代碼必須在時鍾速度方面非常快地運行。 該算法已經在O(N)中。 它需要2秒,需要1秒。 對於大多數A.length輸入,大約100,000,它需要0.3秒,除非特定的代碼行被調用了極端的次數。 (對於深奧的編程挑戰)

它使用一種計算公式,即1,2,.N-> 1,3,4,10,15 ..可以由n *(n + 1)/ 2個I循環表示,通過該方程式有數百個成千上萬次。 我無法訪問輸入,也無法顯示它。 我能夠獲得的唯一信息是運行時間。 特別是等式是:

s+=(n+c)-((n*(n+1))/2);

s和c的值可以是0到10億

n的范圍可以從0到100,000

根據時鍾速度編寫此語句的最有效方法是什么? 我聽說除法需要更多的時間然后乘法,但除此之外,我無法確定在一行或多個賦值行中寫這個是否更有效。 除以乘法再乘以然后除以? 創建自定義整數類型也有很大幫助嗎?

根據請求編輯,帶有小輸入案例的完整代碼(對不起,如果它很難看,我只是繼續剝離它):

public static void main(String[] args) {

        int A[]={3,4,8,5,1,4,6,8,7,2,2,4};//output 44
        int K=6;
        //long start = System.currentTimeMillis();;
        //for(int i=0;i<100000;i++){
            System.out.println(mezmeriz4r(A,K));
        //}
        //long end = System.currentTimeMillis();;

//      System.out.println((end - start) + " ms");

    }
    public static int mezmeriz4r(int[]A,int K){
        int s=0;
        int ml=s;
        int mxl=s;
        int sz=1;
        int t=s;
        int c=sz;
        int lol=50000;
        int end=A.length;
        for(int i=sz;i<end;i++){
            if(A[i]>A[mxl]){
                mxl=i;
            }else if(A[i]<A[ml]){
                ml=i;
            }
            if(Math.abs(A[ml]-A[mxl])<=K){
                sz++;
                if(sz>=lol)return 1000000000;
                if(sz>1){
                    c+=sz;
                }
            }else{
                if(A[ml]!=A[i]){
                    t=i-ml;
                    s+=(t+c)-((t*(t+1))/(short)2);
                    i=ml;
                    ml++;
                    mxl=ml;
                }else{
                    t=i-mxl;
                    s+=(t+c)-((t*(t+1))/(short)2);
                    i=mxl;
                    mxl++;
                    ml=mxl;
                }
                c=1;
                sz=0;
            }
        }
        if(s>1000000000)return 1000000000;
        return s+c;
    }

從挑戰返回:

檢測到的時間復雜度:

上)

測試時間結果

示例測試0.290秒。

單個單個元素0.290 s。

雙重兩個元素0.290 s。

小功能小功能測試0.280秒。

small_random小隨機序列長度= ~100 0.300 s。

small_random2小隨機序列長度=〜100 0.300 s。

medium_random混沌介質序列長度=〜3,000 0.290 s。

large_range大范圍測試,長度= ~100,000 2.200 s。 超時錯誤運行時間:> 2.20秒,時間限制:1.02秒。

large_random隨機大序列長度= ~100,000 0.310 s。

large_answer測試,答案很大,為0.320秒。

large_extreme所有最大值= ~100,000 0.340 s。

有了一點代數,您可以簡單地將表達式(n+c)-((n*(n+1))/2)c-((n*(n-1))/2)來刪除加法運算。 然后,您可以將除法值替換為2 ,向右移位1 ,這比除法更快。 嘗試更換

s+=(n+c)-((n*(n+1))/2);

s+=c-((n*(n-1))>>1);

我會嘗試以下內容並在每次更改后對代碼進行分析,以檢查速度是否有任何增益。


更換:

if(Math.abs(A[ml]-A[mxl])<=K)

通過

int diff = A[ml]-A[mxl];
if(diff<=K && diff>=-K)

更換

/2

通過

>>1

更換

ml++;
mxl=ml;

通過

mxl=++ml;

也許避免對同一元素的數組訪問(java的內部邊界檢查可能需要一些時間)

所以staore至少A[i]在局部變量中。

在for循環中刪除System.out.println():)您會驚訝於計算速度有多快

嵌套分配,即代替

t=i-ml;
s+=(t+c)-((t*(t+1))/(short)2);
i=ml;
ml++;
mxl=ml;

就像是

s+=((t=i-ml)+c);
s-=((t*(t+1))/(short)2);
i=ml;
mxl=++ml;

有時發生在OpenJDK源代碼中。 它主要導致用*dup s替換*load字節碼指令。 根據我的實驗,它確實提供了非常小的加速,但它是超強的,我不建議手動編寫這樣的代碼。

我無權驗證所有輸入。 和時間范圍。 但這肯定是O(N)。 並有所改善。 跑,讓我知道你的反饋。如有必要,我會提供詳細信息

public static int solution(int[]A,int K){
    int minIndex=0;
    int maxIndex=0;
    int end=A.length;
    int slize = end;
    int startIndex = 0;
    int diff = 0;
    int minMaxIndexDiff = 0;
    for(int currIndex=1;currIndex<end;currIndex++){
        if(A[currIndex]>A[maxIndex]){
            maxIndex=currIndex;
        }else if(A[currIndex]<A[minIndex]){
            minIndex=currIndex;
        }
        if( (A[maxIndex]-A[minIndex]) >K){
            minMaxIndexDiff= currIndex- startIndex;
            if (minMaxIndexDiff > 1){
                slize+= ((minMaxIndexDiff*(minMaxIndexDiff-1)) >> 1);
                if (diff > 0 ) {
                    slize = slize + (diff * minMaxIndexDiff);
                }
            }

            if (minIndex == currIndex){
                diff = currIndex - (maxIndex + 1);
            }else{
                diff = currIndex - (minIndex + 1);
            }
            if (slize > 1000000000) {
                return 1000000000;
            }
            minIndex = currIndex;
            maxIndex = currIndex;
            startIndex = currIndex;
        }
    }
    if ( (startIndex +1) == end){
        return slize;
    }
    if (slize > 1000000000) {
        return 1000000000;
    }
    minMaxIndexDiff= end- startIndex;
    if (minMaxIndexDiff > 1){
        slize+= ((minMaxIndexDiff*(minMaxIndexDiff-1)) >> 1);
        if (diff > 0 ) {
            slize = slize + (diff * minMaxIndexDiff);
        }
    }

    return slize;
}

if(Math.abs(A[ml]-A[mxl])<=通過更快的自我計算的abs版本(內聯,而不是方法調用),我會嘗試消除這一行!

轉換為(短)沒有幫助,但嘗試右移位運算符X >> 1而不是x / 2

刪除System.out.println()可以加速1000倍。但是要小心,否則你的整個算法可以被VM刪除因為你不使用它。 舊代碼:

for(int i=0;i<100000;i++){
            System.out.println(mezmeriz4r(A,K));
}

新代碼:

int dummy = 0;
    for(int i=0;i<100000;i++){
          dummy =   mezmeriz4r(A,K);
    }
//Use dummy otherwise optimisation can remove  mezmeriz4r
System.out.print("finished: " + dummy);

我將首先創建一個C版本,然后看看“直接訪問金屬”可以執行多快。 您可能正在嘗試優化已經優化到極限的計算。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM