2011-10-11 18 views
5

Estoy escribiendo una aplicación que requiere etiquetas de redondeo al número "bonito" más cercano. Pondré algunos códigos debajo para demostrar esto, pero mi problema es que estaba usando una serie de ifs adicionales para encontrar este número, pero no puedo estar seguro del límite superior, así que esta no es realmente una buena estrategia. ¿Hay algún algoritmo o recurso conocido que pueda ayudarme?redondear al número agradable más cercano

if (diff <= 1) { 
     roundAmount = 0.2; 
    } else if (diff <= 5) { 
     roundAmount = 1; 
    } else if (diff <= 10) { 
     roundAmount = 2; 
    } else if (diff <= 25) { 
     roundAmount = 5; 
    } else if (diff <= 50) { 
     roundAmount = 10; 
    } else if (diff <= 100) { 
     roundAmount = 20; 
    } else if (diff <= 250) { 
     roundAmount = 50; 
    } else if (diff <= 500) { 
     roundAmount = 100; 
    } else if (diff <= 1000){ 
     roundAmount = 200; 
    } etc... 
+0

Solo puede aplicar un algoritmo si puede definir reglas específicas para qué 'redondeo' realmente es * is *. ¿Tiene esas reglas en mente? Es difícil de decir de su código publicado. – Qwerky

+0

¿Cómo funcionaría ese redondeo, es decir, cómo se podría definir ese número "agradable"? Por ejemplo: 51 se redondearía a 20 (¿es 'roundAmount' el número agradable?) Mientras que 50 se redondea a 10? – Thomas

+0

En este momento, quiero que el redondeo sea un quinto del siguiente número agradable más alto. Un ejemplo más claro podría ser que si tengo los números 1.2, 1.9, 3.65, 4.1, 4.67 me gustaría que las etiquetas se dibujen en 1, 2, 3, 4, 5. – user650309

Respuesta

10

Puede utilizar Math.log10 para normalizar todos los valores antes de hacer su búsqueda "buen número", algo como esto:

[Editar] Me di cuenta de que está utilizando Java en lugar de C#, por lo que modificó el código un poco. No tengo un compilador alrededor de probarlo, pero usted debe conseguir la idea general de todos modos:

static double getNicerNumber(double val) 
{ 
    // get the first larger power of 10 
    var nice = Math.pow(10, Math.ceiling(Math.log10(val))); 

    // scale the power to a "nice enough" value 
    if (val < 0.25 * nice) 
     nice = 0.25 * nice; 
    else if (val < 0.5 * nice) 
     nice = 0.5 * nice; 

    return nice; 
} 

// test program: 
static void main(string[] args) 
{ 
    double[] values = 
    { 
     0.1, 0.2, 0.7, 
     1, 2, 9, 
     25, 58, 99, 
     158, 267, 832 
    }; 

    for (var val : values) 
     System.out.printf("$%.2f --> $%.2f%n", val, getNicerNumber(val)); 
} 

Esto imprimirá algo como:

 
0,1 --> 0,1 
0,2 --> 0,25 
0,7 --> 1 
1 --> 1 
2 --> 2,5 
9 --> 10 
25 --> 50 
58 --> 100 
99 --> 100 
158 --> 250 
267 --> 500 
832 --> 1000
+0

Sí, esto es perfecto. ¡No me di cuenta de que estaba usando C# en lugar de semi-pseudocódigo de todos modos! – user650309

0

me ocurrió con esta solución bastante crudo, que devuelve los valores correctos para todos los casos que probé hace un momento:

public static double foo(long value) { 
    for (double i = 0.2; true; i *= 5) { 
     if (i >= value) { 
      return i/5; 
     } 
    } 
} 

Aunque he de reconocer que una solución matemática tal como fue anunciado por Groo sería más hermoso. ;)

3

prefiero el siguiente sobre el enfoque de Groo, rondas, ya que 267 a 275 en lugar de 500. Básicamente se redondea al primer dígito, y luego la fracción cuarta parte más próxima de dicho poder de 10.

static double round_pretty(double val) { 
    var fraction = 1; 
    var log = Math.floor(Math.log10(val)); 

    // This keeps from adding digits after the decimal 
    if(log > 1) { 
     fraction = 4; 
    } 

    return Math.round(val * fraction * Math.pow(10, -log)) 
     /fraction/Math.pow(10, -log); 
} 

La salida es la siguiente:

0.01 -> 0.01 
0.025 -> 0.03 (Groo's does 0.025) 
0.1 -> 0.1 
0.2 -> 0.2  (Groo's does 0.25) 
0.49 -> 0.5 
0.5 -> 0.5  (Groo's does 1) 
0.51 -> 0.5  (Groo's does 1) 
0.7 -> 0.7  (Groo's does 1) 
1 -> 1 
2 -> 2   (Groo's does 2.5) 
9 -> 9 
23.07 -> 20 
25 -> 30 
49 -> 50 
50 -> 50   (Groo's does 100 here) 
58 -> 60 
94 -> 90 
95 -> 100 
99 -> 100 
100 -> 100 
109 -> 100  (Groo's does 250 here) 
158 -> 150 
249 -> 250 
267 -> 275 
832 -> 825 
1234567 -> 1250000 
1499999 -> 1500000 
1625000 -> 1750000 
Cuestiones relacionadas