如何在C#中以人性化的方式对双打进行双打?

时间:2012-01-31 12:56:32

标签: c# math floating-point rounding

在我的C#程序中,我从某些计算中获得double,其值类似于0,139990,0079996,但此值必须呈现给人类,以便更好地显示分别为0,140,008

所以我需要对值进行舍入,但不知道哪个精度 - 我只需要“丢掉那些噪音数字”。

我怎么能在我的代码中这样做?

澄清 - 我需要在编译时将double值四舍五入到 unknown 的精度 - 这需要在运行时确定。什么是一个很好的启发式来实现这一目标?

8 个答案:

答案 0 :(得分:1)

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,13999
0,0079996
0,00700956

0,14
0008
0007

在你的例子中写下你的数字。

答案 1 :(得分:1)

您似乎想要输出一个与输入值差别不大的值,因此请尝试增加位数,直到达到给定的错误:

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

答案 2 :(得分:0)

您可以在不转换为字符串的情况下执行此操作。这就是我快速创建的:

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

答案 3 :(得分:0)

我可以想到一个解决方案虽然效率不高......

我的假设是,当一个数字处于“最佳”人类可读格式时,如果额外的数字与舍入方式没有区别,你可以判断它是什么。

例如在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这样的东西根本不会被四舍五入。根据给出的例子,我无法说明这是否正确但我认为这是一个双重问题,问题是“正确”值和值为双重的非常小的变化。

答案 4 :(得分:0)

继承我尝试的内容:

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

答案 5 :(得分:0)

在给出另一个想法之后,我做了以下操作,看起来它到目前为止我做了什么。

我迭代了位数并比较Round( value, number )Round( value, number + 1 )。一旦它们相等(当然不是== - 我将差异与较小的数字进行比较),那么number是我正在寻找的数字位数。

答案 6 :(得分:-1)

Double.ToString()可以采用字符串格式作为参数。这将显示您需要的任意数量的字符,四舍五入到小数位。 E.G:

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

将显示“1054.322”。

Source

Generic formats (i.e, pre-generated)

How to generate custom formats

答案 7 :(得分:-4)

您可以在Math.Round函数中使用no数字

Double doubleValue = 4.052102;
Math.Round(doubleValue, 2);

这将返回4.05作为您的要求答案。

这是经过测试的代码,你可以解释一下我的错误。所以我需要改变。