Как округлить двойные в удобной для человека форме в C #? - PullRequest
3 голосов
/ 31 января 2012

В моей программе на C # у меня есть double, полученное из некоторых вычислений, и его значение примерно равно 0,13999 или 0,0079996, но это значение должно быть представлено человеку, поэтому его лучше отображать как 0,14 или 0,008 соответственно.

Так что мне нужно округлить значение, но я не знаю, до какой точности - мне просто нужно «выбросить эти цифры шума».

Как я могу сделать это в моем коде?

Чтобы уточнить - мне нужно округлить значения double с точностью, равной unknown во время компиляции - это нужно определить во время выполнения. Что будет хорошей эвристикой для достижения этой цели?

Ответы [ 8 ]

1 голос
/ 31 января 2012

Похоже, вы хотите вывести значение, которое не очень отличается от входного значения, поэтому попробуйте увеличивать количество цифр, пока не будет достигнута заданная ошибка:

    static double Round(double input, double errorDesired)
    {
        if (input == 0.0) 
            return 0.0;

        for (int decimals = 0; decimals < 17; ++decimals)
        {
            var output = Math.Round(input, decimals);
            var errorAchieved = Math.Abs((output - input) / input);

            if (errorAchieved <= errorDesired)
                return output;
        }

        return input;
    }
}


    static void Main(string[] args)
    {
        foreach (var input in new[] { 0.13999, 0.0079996, 0.12345 })
        {
            Console.WriteLine("{0} -> {1}         (.1%)", input, Round(input, 0.001));
            Console.WriteLine("{0} -> {1}         (1%)", input, Round(input, 0.01));
            Console.WriteLine("{0} -> {1}         (10%)", input, Round(input, 0.1));
        }
    }
1 голос
/ 31 января 2012
private double PrettyRound(double inp)
{
    string d = inp.ToString();
    d = d.Remove(0,d.IndexOf(',') + 1);
    int decRound = 1;
    bool onStartZeroes = true;
    for (int c = 1; c < d.Length; c++ )
    {
        if (!onStartZeroes && d[c] == d[c - 1])
            break;
        else
            decRound++;
        if (d[c] != '0')
            onStartZeroes = false;
    }

    inp = Math.Round(inp, decRound);
    return inp;
}

Тест:

    double d1 = 0.13999; //no zeroes
    double d2 = 0.0079996; //zeroes
    double d3 = 0.00700956; //zeroes within decimal

    Response.Write(d1 + "<br/>" + d2 + "<br/>" + d3 + "<br/><br/>");

    d1 = PrettyRound(d1);
    d2 = PrettyRound(d2);
    d3 = PrettyRound(d3);

    Response.Write(d1 + "<br/>" + d2 + "<br/>" + d3 +"<br/><br/>");

Отпечатки:

0,139990,00799960,007009560,1400080007

Округляет ваши числа, как вы написали в своем примере ..

0 голосов
/ 07 февраля 2012

Подумав еще раз, я сделал следующее и, похоже, пока что делаю то, что хочу.

Я перебираю количество цифр и сравниваю Round( value, number ) и Round( value, number + 1 ). Если они равны (конечно, не == - я сравниваю разницу с небольшим числом), тогда number - это количество цифр, которые я ищу.

0 голосов
/ 31 января 2012

Вот что я пробовал:

public decimal myRounding(decimal number)
{
   double log10 = Math.Log10((double) number);
   int precision = (int)(log10 >= 0 ? 0 : Math.Abs(log10)) + (number < 0.01m ? 1 : 2);
   return  Math.Round(number, precision);
}

тест:

Console.WriteLine(myRounding(0.0000019999m)); //0.000002
Console.WriteLine(myRounding(0.0003019999m)); //0.0003
Console.WriteLine(myRounding(2.56777777m));   //2.57
Console.WriteLine(myRounding(0.13999m));      //0.14
Console.WriteLine(myRounding(0.0079996m));    //0.008
0 голосов
/ 31 января 2012

Я могу думать о решении, хотя оно не очень эффективно ...

Я предполагаю, что вы можете определить, когда число находится в "лучшем" читаемом человеком форматекогда дополнительные цифры не имеют значения для округления.

Например, при округлении 0,13999 до разного числа десятичных разрядов получается:

0
0.1
0.14
0.14
0.14
0.13999

Я бы предложилВы могли бы пройти через цикл и обнаружить этот стабильный патч и обрезать его там.

Этот метод, кажется, делает это:

public double CustomRound(double d)
{
    double currentRound = 0;
    int stability = 0;
    int roundLevel = 0;
    while (stability < 3)
    {
        roundLevel++;
        double current = Math.Round(d, roundLevel);
        if (current == currentRound)
        {
            stability++;
        }
        else
        {
            stability = 1;
            currentRound=current;
        }
    }
    return Math.Round(d, roundLevel);
}

Этот код может быть очищаем, но он выполняет свою работу и является достаточнымдоказательство концепции.:)

Я должен подчеркнуть, что это исходное допущение (отсутствие изменений при округлении) - это критерий, на который мы смотрим, что означает, что что-то вроде 0.3333333333 не будет округлено вообще.С приведенными примерами я не могу сказать, является ли это правильным или нет, но я предполагаю, что если это двойная проблема, то проблема заключается в очень незначительных отклонениях от «правильного» значения и значения в виде двойного.

0 голосов
/ 31 января 2012

Вы можете сделать это без преобразования в строку.Это то, что я создал быстро:

private static double RoundDecimal(double number)
{
   double temp2 = number;
   int temp, counter = 0;

   do
   {
      temp2 = 10 * temp2;
      temp = (int)temp2;

      counter++;
   } while (temp < 1);

   return Math.Round(number, counter < 2 ? 2 : counter);
}

или

private static double RoundDecimal(double number)
{
       int counter = 0;

       if (number > 0) { 
          counter = Math.Abs((int) Math.Log10(number)) + 1;

       return Math.Round(arv, counter < 2 ? 2 : counter);
}
0 голосов
/ 31 января 2012

Вы не можете использовать ни одну из цифр с Math.Round.неправильно.Так что мне нужно изменить.

0 голосов
/ 31 января 2012

Double.ToString() может принимать формат строки в качестве аргумента. Это отобразит столько символов, сколько вам нужно, с округлением до десятичного знака. Например:

double Value = 1054.32179;
MessageBox.Show(Value.ToString("0.000"));

Появится «1054.322».

Источник

Универсальные форматы (то есть предварительно сгенерированные)

Как создавать собственные форматы

...