【问题标题】:Custom Rounding of decimal type in C#C#中十进制类型的自定义舍入
【发布时间】:2011-01-27 10:18:13
【问题描述】:

伙计们, 我正在编写一种舍入方法。输入是十进制类型(保证四位小数)。舍入规则是忽略 0.005 或更少,即查看小数点后第三位 - 如果 82.36、82.3667 -> 82.37、82.5967 -> 82.60、82.9958 -> 82.99、82.9968 -> 83.00 有什么好主意吗?我已经解决了如下。

private decimal CustomRound(decimal x)
{
   decimal rX = Math.Truncate(x * 100) / 100;
   decimal x3DecPlaces = Math.Truncate(x * 1000) / 1000;
   decimal t = (x3DecPlaces * 1000) % 10;
   if (t >= 6)
      rX = rX + 0.01m;
   return rX;
}

【问题讨论】:

    标签: c# rounding


    【解决方案1】:

    我不相信有什么内置的,因为这是一个非常不寻常的要求(例如,1.3358 更接近 1.33 而不是 1.34 的想法很奇怪)。您的代码看起来相当合适。

    编辑:你不能在这里使用MidpointRounding 来获得你想要的效果,因为你开始向上取整的点不是中点——它是(比如说)1.336 而不是正常的 1.335。只有 1.335 被视为 1.33 和 1.34 之间的中点,因为 中点。您实际上以一种不同寻常的方式在这里得到了有偏的四舍五入。

    你甚至不能只截断到三个 DP 然后使用MidpointRounding,因为没有“趋向零”模式。

    一个稍微奇怪的选择是自己有效地执行偏差:

    private static decimal CustomRound(decimal x)
    {
        return decimal.Round(x - 0.001m, 2, MidpointRounding.AwayFromZero);
    }
    

    因此它将 82.3657 视为 82.3647 并将其四舍五入为 82.36;它将处理 82.3667 和 82.3657 并将其四舍五入为 82.37,并将 82.5967 视为 82.5957 并将其四舍五入为 82.60 等。我认为可以满足您的要求 - 但仅适用于正值。您需要准确地确定负值所需的行为。

    无论你做什么,你都需要非常清楚地记录下来:)

    出于偏好,我会使用decimal.Truncate 而不是Math.Truncate,只是为了更清楚地说明一切都是用小数完成的。

    【讨论】:

    • 是的,我努力尝试使用内置方法。谢谢。
    【解决方案2】:

    您想如何处理负值?我想你会希望 -13.999 舍入到 -14 而不是 -13.99 对吧?

    在这种情况下,您的+/- 0.01m 应该取决于x 是负数还是正数。

    这是一种更简单的方法:

    decimal CustomRound(decimal x)
    {
        var offset = x >= 0 ? -0.001m : 0.001m;
        return Decimal.Round(x + offset, 2, MidpointRounding.AwayFromZero);
    }
    

    【讨论】:

      【解决方案3】:

      也许你可以使用 Math.Round(Double, Int32) 方法?

      【讨论】:

      • 从十进制转换为双精度然后再转换回来是一个糟糕的主意 - 这意味着使用十进制开始几乎毫无意义。
      • @Jon: 有一个 overloadMath.Round 使用小数。
      • @Vlad:当然可以,但是这个答案专门使用 double 调用了重载。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-10
      • 2011-02-04
      相关资源
      最近更新 更多