我如何在C#中以人性化的方式完成双打
本文关键字:方式完 人性化 | 更新日期: 2023-09-27 18:22:11
在我的C#程序中,我有一个从一些计算中获得的double
,它的值类似于0,13999
或0,0079996
,但这个值必须呈现给人类,这样它才能更好地分别显示为0,14
或0,008
。
所以我需要四舍五入这个值,但不知道精确到什么程度——我只需要"扔掉那些噪音数字"。
我怎么能在代码中做到这一点?
为了澄清——我需要在编译时将double
值四舍五入到未知的精度——这需要在运行时确定。实现这一点的好的启发式方法是什么?
您似乎想要输出一个与输入值没有太大差异的值,所以请尝试增加位数,直到出现给定错误:
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作为您所需的答案。
这是经过测试的代码,你能解释我怎么错了吗。所以我需要改变。