2012-05-02 18 views
11

Tôi có hai thời gian không âm. Chúng có thể lớn, gần Long.MAX_VALUE. Tôi muốn tính tỷ lệ phần trăm từ hai số.Cách tràn an toàn để tính phần trăm từ hai lần trong Java

Thường thì tôi muốn làm điều này:

long numerator = Long.MAX_VALUE/3 * 2; 
    long denominator = Long.MAX_VALUE; 

    int percentage = (int) (numerator * 100/denominator); 
    System.out.println("percentage = " + percentage); 

Đây không phải là chính xác nếu tử số là trong vòng hai thứ tự của độ lớn để Long.MAX_VALUE.

Cách chính xác, đơn giản và nhanh chóng là gì?

Trả lời

12

Tôi muốn sử dụng:

int percentage = (int)(numerator * 100.0/denominator + 0.5); 

Các 100.0 lực lượng nổi-điểm toán từ thời điểm đó trở đi, và + 0.5 vòng số nguyên gần nhất thay vì cắt bỏ.

+0

Tại sao '+ 0,5' ở cuối? Tôi đoán nó là để làm tròn tốt hơn ... nhưng 99,6 sau đó sẽ là 100 mà có lẽ không tốt như vậy –

+1

@SteveMcLeod: Vâng, đó là để làm với làm tròn (xem câu trả lời được cập nhật). Tôi nghĩ rằng làm tròn đến gần nhất là một mặc định hợp lý. – NPE

+1

Giải pháp này tôi thích. –

7
int percentage = (int) (0.5d + ((double)numerator/(double)denominator) * 100); 

Nếu bạn chia một long với một long bạn sẽ nhận được một long, đó là không tốt cho tỷ lệ phần trăm.

2

Cách tầm thường là chuyển đổi cả hai thành float hoặc double trước khi thực hiện phép tính, với chi phí mất chính xác một chút. Nó cũng chậm, so với các lựa chọn thay thế.

Một cách khác là chia từng giá trị thành hai thành phần 32 bit và thực hiện phép nhân và chia dài.

2

Trừ khi tôi là thiếu một cái gì đó rõ ràng không thể bạn chỉ cần viết:

public class round { 
    public static void main(String[] argv) { 
    long numerator = Long.MAX_VALUE/3 * 2; 
    long denominator = Long.MAX_VALUE; 

    int percentage = (int) (numerator/(denominator/100)); 
    System.out.println("percentage = " + percentage); 

    } 
} 

để thay thế? I E. Thay vì làm cho tử số lớn hơn trước khi phân chia làm cho mẫu số nhỏ hơn. Vì bạn biết mẫu số lớn nên không có rủi ro nào mà bộ phận sẽ cho 0, đó là lý do thường viết (n * 100)/d khi bạn không sử dụng số dấu phẩy động.

+0

Điều này dường như hoạt động. –

+0

@SteveMcLeod - Tôi nghĩ nó đúng cho trường hợp bạn có số nguyên và biết chúng lớn. Cách viết thông thường được thiết kế để đối phó với những trường hợp chúng nhỏ. – Flexo

0

Những người thực hiện theo cách sau vì được đề xuất thực hiện các phép tính với BigDecimal và BigInteger. Đây là triển khai:

BigDecimal n = new BigDecimal(Long.MAX_VALUE); 
    BigDecimal d = new BigDecimal(Long.MAX_VALUE); 
    BigDecimal i = new BigDecimal(100); 
    int percentage = n.multiply(i).divide(d).intValue(); 
    System.out.println(percentage);