2012-05-02 6 views
11

Tengo dos largos no negativos. Pueden ser grandes, cerca de Long.MAX_VALUE. Quiero calcular un porcentaje de los dos números.Forma segura de desbordamiento para calcular el porcentaje de dos largos en Java

Por lo general, me gustaría hacer esto:

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

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

Esto no es correcto si el numerador es el plazo de dos magnitudes a fin de Long.MAX_VALUE.

¿Cuál es la forma correcta, simple y rápida de hacerlo?

Respuesta

12

que haría uso:

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

Las fuerzas 100.0 matemáticas de punto flotante a partir de ese momento, y las rondas + 0.5 al entero más cercano en lugar de truncar.

+0

¿Por qué el '+ 0.5' al final? Supongo que es para dar un mejor redondeo ... pero 99.6 sería 100, que tal vez no sea tan bueno –

+1

@SteveMcLeod: Sí, tiene que ver con el redondeo (ver la respuesta actualizada). Creo que redondear al más cercano es un valor predeterminado razonable. – NPE

+1

Esta solución me gusta. –

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

Si divide un long con un long obtendrá un long, que no es bueno para los porcentajes.

2

La manera trivial es convertir ambos a float o double antes de hacer el cálculo, a expensas de una ligera pérdida de precisión. También es lento, en comparación con las alternativas.

Una alternativa es dividir cada valor en dos componentes de 32 bits, y hacer una multiplicación larga y una división larga.

2

A menos que me falta algo obvio no puede usted acaba de escribir:

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

    } 
} 

en su lugar? Es decir. En lugar de hacer que el numerador sea más grande antes de la división, reduzca el denominador. Como sabes que el denominador es grande, no hay riesgo de que la división dé 0, que es la razón por la que usualmente escribes (n * 100)/d cuando no estás usando números de coma flotante.

+0

Esto parece funcionar. –

+0

@SteveMcLeod: creo que es correcto para el caso en que tengas números enteros y sepas que son grandes. La forma habitual de escribir está diseñada para hacer frente a casos en que son pequeños. – Flexo

0

Los chicos implementan de la siguiente manera porque se sugiere hacer cálculos con BigDecimal y BigInteger. Aquí está la implementación:

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