2012-05-18 27 views
10

Tôi cần phải đối phó với rất nhiều số lớn lớn hơn nhiều so với dài (> 10^200), vì vậy tôi đang sử dụng BigIntegers. Các hoạt động phổ biến nhất mà tôi thực hiện được thêm chúng vào một accumulator, ví dụ:Java có thể tối ưu hóa "đột biến" các hoạt động BigInteger trong các vòng lặp không?

BigInteger A = new BigInteger("0"); 
for(BigInteger n : nums) { 
    A = A.add(n); 
} 

Tất nhiên tạo bản sao cho những hành động phá hoại là khá một sự lãng phí (tốt, miễn là có một bộ đệm đủ lớn có sẵn), vì vậy tôi đã tự hỏi nếu Java có thể tối ưu hóa điều này bằng cách nào đó (tôi nghe nói có một lớp MutableBigInteger không được tiếp xúc bởi math.java) hoặc liệu tôi có nên viết lớp BigInteger của riêng tôi hay không.

+8

Nó có thể tối ưu gián tiếp theo một vài cách: ví dụ: có thể * hầu hết * phiên bản mới (ngoại trừ lần cuối) trực tiếp rất, rất ngắn và không bao giờ rời khỏi phương pháp và do đó tối ưu hóa cách phân bổ bộ nhớ của chúng. Điều này có nghĩa là * rất khó dự đoán hiệu suất của mã này. Bạn đã chuẩn bị * mã của bạn và * đã được chứng minh * rằng mã này có phải là nút cổ chai không? –

+0

Trong trường hợp bạn cần sử dụng lớp Integer có thể thay đổi, hãy xem: [package org.apache.commons.lang.mutable] (http://commons.apache.org/lang/api-2.4/org/ apache/commons/lang/mutable/package-summary.html). – anubhava

+0

@anubhava: Thật tốt khi biết các lớp này, nhưng tôi không thấy chúng sẽ giúp gì cho câu hỏi này. – NPE

Trả lời

2

Có, có một lớp học java.math.MutableBigInteger được sử dụng bởi BigInteger cho các hoạt động tính toán chuyên sâu. Thật không may, nó được khai báo là gói riêng tư, vì vậy bạn không thể sử dụng nó. Ngoài ra còn có một "MutableBigInteger" lớp trong thư viện Apache Commons, nhưng nó chỉ là một wrapper mutable cho BigInteger và đó không phải là giúp đỡ cho bạn.

Tôi đã tự hỏi nếu Java có thể tối ưu hóa này bằng cách nào đó ...

Không ... không chịu được ở trên.

hoặc liệu tôi có nên viết lớp BigInteger của riêng mình không.

Đó là một cách tiếp cận.

Một cách khác là tải xuống các nguồn OpenJDK, tìm mã nguồn cho java.math.MutableBigInteger, thay đổi tên gói và quyền truy cập của nó và kết hợp nó vào mã cơ sở của bạn. Chỉ có snag là OpenJDK được cấp phép theo GPL (GPL-2 tôi nghĩ), và điều đó có ngụ ý nếu bạn từng phân phối mã bằng cách sử dụng lớp đã sửa đổi.

Xem thêm:

2

Một giải pháp nhanh hơn là để phá vỡ khả năng hiển thị gói java. Bạn có thể làm điều đó bằng cách tạo ra một gói có tên java.math trong dự án của riêng bạn và tạo ra một lớp nào đó cho thấy nhiều gói MutableBigInteger tin như vậy:

package java.math; 

public class PublicMutableBigInteger extends MutableBigInteger { 

} 

Sau đó, bạn chỉ có thể nhập java.math.PublicMutableBigInteger; và sử dụng nó như bất kỳ lớp nào khác. Giải pháp này nhanh chóng và không áp đặt cho bạn bất kỳ giấy phép cụ thể nào.

+0

Nếu bạn đang tiêm một lớp mới vào 'java.math' (đó là phá vỡ "các quy tắc") để phá vỡ các hạn chế truy cập, bạn cũng có thể đi toàn bộ con heo và sửa đổi các lớp học truy cập. Cùng một sự khác biệt thực sự ... –

+0

@Stephen C Bạn đang cố gắng nói gì? Tôi không hiểu bạn Tiêm lớp mới vào java.math chắc chắn nhanh hơn và dễ dàng hơn. –

+0

Tôi có nghĩa là các vấn đề như thế này ... http://stackoverflow.com/questions/860187/access-restriction-on-class-due-to-restriction-on-required-library-rt-jar –

2

Không có nhiều trình biên dịch có thể làm, bởi vì nó không thể biết phương thức add làm gì. Đây là mã được tạo ra cho phần thân của vòng lặp. Như bạn có thể thấy, nó chỉ đơn giản là gọi add và lưu trữ kết quả.

25: iload 5 
    27: iload 4 
    29: if_icmpge  51 
    32: aload_3 
    33: iload 5 
    35: aaload 
    36: astore 6 
    38: aload_1 
    39: aload 6 
    41: invokevirtual #5; //Method java/math/BigInteger.add:(Ljava/math/BigInteger;)Ljava/math/BigInteger; 
    44: astore_1 
    45: iinc 5, 1 
    48: goto 25 

Về lý thuyết, hệ thống thời gian chạy máy ảo Java có thể thông minh hơn. Ví dụ, nó có thể phát hiện rằng một đối tượng liên tục ghi đè lên một đối tượng khác chỉ được cấp phát và chỉ trao đổi hai bộ đệm phân bổ cho chúng. Tuy nhiên, như chúng ta có thể thấy bằng cách chạy chương trình sau đây với ghi nhật ký thu gom rác được bật, điều này thật đáng buồn không phải là trường hợp

import java.math.BigInteger; 
import java.util.ArrayList; 
import java.util.Random; 

class Test { 
    public static void main(String[] args) { 
    ArrayList <BigInteger> nums = new ArrayList<BigInteger>(); 
    final int NBITS = 100; 
    final int NVALS = 1000000; 

    System.out.println("Filling ArrayList"); 
    Random r = new Random(); 
    for (int i = 0; i < NVALS; i++) 
     nums.add(new BigInteger(NBITS, r)); 

    System.out.println("Adding ArrayList values"); 
    BigInteger A = new BigInteger("0"); 
    for(BigInteger n : nums) { 
     A = A.add(n); 
    } 

    System.gc(); 
    } 
} 

Xem các cuộc gọi thu gom rác trong quá trình bổ sung.

C:\tmp>java -verbose:gc Test 
Filling ArrayList 
[GC 16256K->10471K(62336K), 0.0257655 secs] 
[GC 26727K->21107K(78592K), 0.0304749 secs] 
[GC 53619K->42090K(78592K), 0.0567912 secs] 
[Full GC 42090K->42090K(122304K), 0.1019642 secs] 
[GC 74602K->65857K(141760K), 0.0601406 secs] 
[Full GC 65857K->65853K(182144K), 0.1485418 secs] 
Adding ArrayList values 
[GC 117821K->77213K(195200K), 0.0381312 secs] 
[GC 112746K->77245K(228288K), 0.0111372 secs] 
[Full GC 77245K->137K(228288K), 0.0327287 secs] 

C:\tmp>java -version 
java version "1.6.0_25" 
Java(TM) SE Runtime Environment (build 1.6.0_25-b06) 
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode) 
+0

Bạn cũng có thể mô tả cách thức để tạo ra danh sách lắp ráp đó? –

+0

Bạn chỉ cần chạy '' 'javap -c Test''' –

+0

Tất nhiên, tôi phải đang ngủ. Đó là bytecode java, không phải là hotspots tạo ra assembler. Như vậy nó không nói nhiều về hiệu suất thực tế sau khi jit đã thực hiện phép thuật của nó. –

0

Java sẽ không thực hiện bất kỳ tối ưu hóa đặc biệt nào cho trường hợp này. BigInteger thường được coi là một lớp bình thường giống như bất kỳ lớp nào khác (không giống như String, ví dụ, đôi khi được một số tối ưu hóa đặc biệt khi bạn đang nối nhiều chuỗi).

Nhưng trong hầu hết các trường hợp, BigInteger đủ nhanh để không quan trọng. Nếu bạn thực sự nghĩ rằng đó có thể là một vấn đề, tôi khuyên bạn nên lập hồ sơ và viết ra những gì đang diễn ra.

Nếu thêm BigIntegers thực sự là nút cổ chai của bạn, thì có thể có ý nghĩa khi sử dụng lớp có số lượng lớn có thể thay đổi tùy chỉnh để hoạt động như một bộ tích lũy. Nhưng tôi sẽ không làm điều này trước khi bạn chứng minh rằng đây thực sự là nút cổ chai chính.

Các vấn đề liên quan