在不损失精度的情况下四舍五入到最佳单位

时间:2010-01-26 16:16:26

标签: c# vb.net

我收到“。”后最多4位的十进制数字。我知道这个数字是毫克。

我必须找到最佳匹配单位(毫克,克,千克)。

如果我收到

的例子

编辑

  

116000000.0000毫克,它将返回116.0000千克
  66990000.0000毫克,它将返回66.9900千克
  49000010.0000毫克,它将返回49000.0100克   49000000.0100毫克,它将返回49000000.0100毫克
  1001毫克,它将返回1.0010克
  1010毫克,它将返回1.0100克
  1000毫克,它将返回0.0010千克
  1100毫克,它将返回0.0011千克
  135005毫克,它将返回135.0050克
  最后样品10013500毫克,它将返回10.0135千克

我目前正在使用此代码 ,我觉得它看起来很丑陋而且可能会失败

Dim temp As Decimal
Dim u = New List(Of Integer)(New Integer() {1, 1000, 1000000})
For i = 0 To u.Count - 1
    temp = CDec(qty / u(i))
    If (temp * 10000) - Math.Truncate(temp * 10000) <> 0 AndAlso (temp * 10000) - Math.Truncate(temp * 10000) < 1 Then
        temp = CDec(qty / u(i - 1))
        Exit For
    End If
Next
qty = temp

有没有更好/更好的方式来做我做的事情?

编辑精确度

输入可以是0.0001和小数在.net

中可以接受的最大值之间的任何小数

输出需要四舍五入到最佳单位,“。”后最多4位数。不会丢失任何精度

6 个答案:

答案 0 :(得分:3)

生成数字并选择合适的数字。

    public static decimal FormatDecimal(decimal i)
    {
        decimal milli = i;
        decimal grams = decimal.Round(i / 1000m, 4);
        decimal kilo = decimal.Round(grams / 1000m, 4);

        if (kilo * 1000 * 1000 == milli)
        {
            return kilo;
        }
        if (grams * 1000 == milli)
        {
            return grams;
        }
        return milli;
    }

并测试:

    public static void FormatDecimalTest()
    {
        if (FormatDecimal(116000000.0000m) == 116.0000m)
            Console.WriteLine("ok1");
        if (FormatDecimal(66990000.0000m) == 66.9900m)
            Console.WriteLine("ok2");
        if (FormatDecimal(49000010.0000m) == 49000.0100m)
            Console.WriteLine("ok3");
        if (FormatDecimal(49000000.0100m) == 49000000.0100m)
            Console.WriteLine("ok4");
        if (FormatDecimal(1001m) == 1.0010m)
            Console.WriteLine("ok5");
        if (FormatDecimal(1000m) == 0.0010m)
            Console.WriteLine("ok6");
        if (FormatDecimal(1100m) == 0.0011m)
            Console.WriteLine("ok7");
        if (FormatDecimal(1100m) == 0.0011m)
            Console.WriteLine("ok8");
        if (FormatDecimal(135005m) == 135.0050m)
            Console.WriteLine("ok9");
        if (FormatDecimal(10013500m) == 10.0135m)
            Console.WriteLine("ok10");
    }

在你的问题中,我看到你对各种因素进行了循环。这是一个循环解决方案,它将找到不失精度的第一个因素。

    public static decimal FormatDecimal(decimal i)
    {
        List<decimal> myFactors = new List<decimal>()
        { 1000m * 1000m, 1000m};

        foreach (decimal conversionFactor in myFactors)
        {
            decimal result = decimal.Round(i / conversionFactor, 4);
            if (result * conversionFactor == i)
            {
                return result;
            }
        }

        return i;
    }

答案 1 :(得分:0)

你的样本没有多大意义,但你应该这样做:

static string FormatWeight(double value)
{
    if (value > 10000000) return (value / 10000000D).ToString("0.#### t");
    if (value > 100000) return (value / 100000D).ToString("0.#### kg");
    if (value > 1000) return (value / 1000D).ToString("0.#### g");
    return value.ToString("0.#### mg");
}

答案 2 :(得分:0)

为什么不用ifs?类似的东西:

if (num > 1000000) 
return string.format("{0.####} kg", num/1000000)

if (num > 1000) 
return string.format("{0.####} g", num/1000);

return string.format("{0.####} mg", num);

答案 3 :(得分:0)

我不会在数字上做CStr,计算字符,删除所有尾随零,再次计算数字,并根据字符串中的字符数决定单位。然后将原始数字除以正确的幅度并附加单位。

在此之前,您需要对原始文件执行截断操作,并查看返回的值是否与原始值匹配;然后你只需要使用mg。

可能不会比您的代码更好地工作,但它可能更容易阅读。也许

答案 4 :(得分:0)

你是不是更好地为转换实现或使用单位库,然后格式化结果?

某些项目herehere,虽然我不能保证任何项目的质量......

和java讨论了here

答案 5 :(得分:0)

所以,如果我理解正确,任何带有分数&lt;&gt;的ARG参数0将保持原样并以mg表示...这应该很容易编码

If ARG <> Int(ARG) Then
   ' Return ARG
Endif

任何没有分数的东西都应转换为最合适的单位(mg,g,dag,kg,t等)。所以对于这些我们需要将参数看作一个字符串并从后端计算“0”,并从中看到我们在不丢失数字精度的情况下除以10的频率。

在你的第一个例子中,我们从后端计算了6个零,所以我们可以安全地除以10 ^(6 + 4)得到不超过4个小数位数(这比我们实际需要的多)。

在你的上一个例子中,我们从后面计算2“0”es,所以我们可以安全地除以10 ^(2 + 4)。

因此,如果“保存分割能力”> = 6,则除以10 ^ 6并以kg表示 如果“保存分配能力在5到3之间,除以10 ^ 3并以g表示,低于3则以mg为单位。

希望有所帮助。