округлить до ближайшего красивого номера - PullRequest
5 голосов
/ 11 октября 2011

Я пишу приложение, которое требует округления меток до ближайшего «хорошего» числа.Ниже я приведу код, чтобы продемонстрировать это, но моя проблема в том, что я использовал ряд других if, чтобы найти это число, но я не могу быть уверен в верхнем пределе, так что это не очень хорошая стратегия.Есть какие-нибудь известные алгоритмы или ресурсы, которые могут мне помочь?

    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...

Ответы [ 3 ]

10 голосов
/ 11 октября 2011

Вы можете использовать Math.log10, чтобы нормализовать все значения перед выполнением поиска "хорошего числа", что-то вроде этого:

[Edit] Я только что понял, что вы используете Java вместо C #, поэтому я немного изменил код. У меня нет компилятора для его тестирования, но вы все равно должны получить общее представление:

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

Это напечатает что-то вроде:

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
3 голосов
/ 28 января 2012

Я предпочитаю следующее, чем подход Гроо, так как он округляет 267 до 275 вместо 500. Он в основном округляется до первой цифры, а затем до ближайшей четвертой доли этой степени 10.Вывод выглядит следующим образом:

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
0 голосов
/ 11 октября 2011

Я придумал это довольно грубое решение, которое возвращает правильные значения для всех случаев, которые я только что тестировал:

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

Хотя я должен признать, что математическое решение, опубликованное Гроо, было бы более красивым. ;)

...