2012-05-02 13 views
11

Mam dwa nieujemne długie. Mogą być duże, zbliżone do Long.MAX_VALUE. Chcę obliczyć procent z dwóch liczb.Przepełnienie - bezpieczny sposób obliczania wartości procentowej z dwóch liczb długich w Javie

Zwykle bym to zrobić:

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

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

To nie jest poprawne, jeśli licznik jest w dwóch rząd wielkości do Long.MAX_VALUE.

Co to jest poprawny, prosty i szybki sposób to zrobić?

Odpowiedz

12

użyję:

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

W 100.0 sił zmiennoprzecinkową matematyki od tego momentu, a + 0.5 zaokrągla do najbliższej liczby całkowitej zamiast obcinania.

+0

Dlaczego "+ 0,5" na końcu? Myślę, że to dać lepsze zaokrąglenie ... ale 99,6 byłaby wtedy 100, który jest może nie tak dobre –

+1

@SteveMcLeod: Tak, to zrobić z zaokrągleniem (patrz zaktualizowaną odpowiedź). Myślę, że zaokrąglanie do najbliższych jest rozsądną domyślą. – NPE

+1

To rozwiązanie lubię. –

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

przypadku dzielenia long z long dostaniesz long, że nie jest dobre dla procentach.

2

Najprostszym sposobem jest przekonwertowanie zarówno na float lub double przed wykonaniem obliczeń, kosztem niewielkiej utraty precyzji. Jest także powolny w porównaniu do alternatyw.

Jedną z opcji jest dzielenie każdej wartości na dwie 32-bitowe komponenty, a także długie mnożenie i długie dzielenie.

2

chyba że jestem brakuje czegoś oczywiste, nie można po prostu napisać:

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); 

    } 
} 

zamiast? To znaczy. Zamiast zwiększania licznika przed podziałem, zmniejsz wartość mianownika. Ponieważ wiesz, że mianownik jest duży, nie ma ryzyka, że ​​podział da 0, co jest powodem, dla którego zwykle pisze się (n * 100)/d, gdy nie używasz liczb zmiennoprzecinkowych.

+0

To wydaje się działać. –

+0

@SteveMcLeod - Myślę, że to jest poprawne dla przypadku, gdy masz liczby całkowite i wiesz, że są duże. Zwykły sposób pisania jest przeznaczony do radzenia sobie z przypadkami, w których są one małe. – Flexo

0

Faceci wdrażają w następujący sposób, ponieważ sugeruje się wykonywanie obliczeń za pomocą BigDecimal i BigInteger. Oto realizacja:

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); 
Powiązane problemy