2011-10-11 17 views
5

Piszę wniosek, który wymaga zaokrąglenia etykiet do najbliższego "miły" numer. Podam poniższy kod, żeby to zademonstrować, ale moim problemem jest to, że użyłem serii innych znaków if, aby znaleźć ten numer, ale nie mogę być pewien górnego limitu, więc nie jest to dobra strategia. Czy są jakieś znane algorytmy lub zasoby, które mogłyby mi pomóc?runda do najbliższego miłego numeru

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

można zastosować tylko algorytm, jeśli można określić szczególne przepisy dotyczące tego, co „miły” zaokrąglania faktycznie * to *. Czy masz na myśli takie zasady? Trudno powiedzieć z twojego opublikowanego kodu. – Qwerky

+0

Jak to zaokrąglanie, czyli jak można zdefiniować te "ładne" liczby? Na przykład: 51 zostanie zaokrąglone do 20 (czy "roundAmount" to fajna liczba?), Podczas gdy 50 jest zaokrąglone do 10? – Thomas

+0

W tym momencie chciałbym, aby zaokrąglenie było piątą z następnej najwyższej, ładnej liczby. Bardziej czytelnym przykładem może być to, że jeśli mam numery 1,2, 1,9, 3,65, 4,1, 4,67, chciałbym, aby etykiety narysowane na 1, 2, 3, 4, 5. – user650309

Odpowiedz

10

Można użyć Math.log10 znormalizować wszystkie wartości przed robi swoje „ładny numer” wyszukiwanie, coś takiego:

[Edytuj] Właśnie uświadomiłem sobie używasz Java zamiast C#, więc trochę zmodyfikował kod. Nie mam kompilatora wokół go przetestować, ale należy uzyskać ogólne pojęcie i tak:

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

To będzie drukować coś takiego:

 
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

Tak, to jest idealne. Nie zdawałem sobie sprawy, że mimo to używasz C# zamiast pół-pseudokodowania! – user650309

0

wymyśliłem tego dość surowego roztworu, która zwraca poprawne wartości dla wszystkich badanych przypadkach I właśnie teraz:

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

Chociaż muszę przyznać, że matematycznym rozwiązanie jako wysłane przez Groo byłby piękniejszy. ;)

3

Preferuję nad podejściem Groo, tak jak to zaokrągla 267 do 275 zamiast 500. To w zasadzie zaokrągla do pierwszej cyfry, a następnie najbliższą część czwarta tego potęgi 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); 
} 

wyjście jest w następujący sposób:

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