我如何在C#中以人性化的方式完成双打

本文关键字:方式完 人性化 | 更新日期: 2023-09-27 18:22:11

在我的C#程序中,我有一个从一些计算中获得的double,它的值类似于0,139990,0079996,但这个值必须呈现给人类,这样它才能更好地分别显示为0,140,008

所以我需要四舍五入这个值,但不知道精确到什么程度——我只需要"扔掉那些噪音数字"。

我怎么能在代码中做到这一点?

为了澄清——我需要在编译时将double值四舍五入到未知的精度——这需要在运行时确定。实现这一点的好的启发式方法是什么?

我如何在C#中以人性化的方式完成双打

您似乎想要输出一个与输入值没有太大差异的值,所以请尝试增加位数,直到出现给定错误:

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

打印:

013999
00079996
000700956

0,14
0008
0007

按照你在示例中所写的内容对你的数字进行四舍五入。。

我可以认为是一个解决方案,尽管它不是很有效。。。

我的假设是,当额外的数字对四舍五入的方式没有影响时,你可以判断一个数字何时是"最好的"人类可读格式。

例如,在013999的例子中,将其四舍五入到各种小数位数得出:

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之类的东西根本不会被四舍五进。在给出的例子中,我无法判断这是否正确,但我认为如果这是双重问题,那么问题在于"正确"值和双重值之间的微小变化。

以下是我尝试的:

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

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

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

在对它进行了另一次思考之后,我做了以下操作,到目前为止,它似乎达到了我想要的效果。

我对位数进行迭代,并比较Round( value, number )Round( value, number + 1 )。一旦它们相等(当然不是==——我将差值与一个小数字进行比较),那么number就是我要找的位数。

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

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

将显示"1054.322"。

通用格式(即预生成)

如何生成自定义格式

您可以在Math.Round函数中使用个位数

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

这将返回4.05作为您所需的答案。

这是经过测试的代码,你能解释我怎么错了吗。所以我需要改变。