我决定重新提出我的问题:

decimal dTotal = 0m;
foreach (DictionaryEntry item in _totals)
    {
        if (!string.IsNullOrEmpty(item.Value.ToString()))
        {
            dTotal += Convert.ToDecimal(item.Value);
        }
    }
    Console.WriteLine(dTotal / 3600m);
    Console.WriteLine(decimal.Round(dTotal / 3600m, 2));
    Console.WriteLine(decimal.Divide(dTotal, 3600m));


上面的代码返回:


  579.99722222222222222222222222
  
  580.00
  
  579.99722222222222222222222222


因此,这就是我的问题出处,我真的需要它来显示579.99;但是任何回合,无论是decimal.Round还是Math.Round仍返回580;甚至{0:F}的字符串格式也返回580.00

我该如何正确地做到这一点?

最佳答案

新答案(对新问题)

好的,所以您有一个579.99722222222222222222222222值-您要求将其四舍五入到两位小数。 580.00不是自然的答案吗?比579.99更接近原始值。听起来您本质上想要地板行为,但是具有给定的数字位数。为此,您可以使用:

var floored = Math.Floor(original * 100) / 100;


在这种情况下,您可以一步完成两个操作:

var hours = Math.Floor(dTotal / 36) / 100;


...相当于

var hours = Math.Floor((dTotal / 3600) * 100) / 100;


原始答案(针对原始问题)

听起来您可能以payTotal开头不正确的形式是:

using System;

class Test
{
    static void Main()
    {
        decimal pay = 2087975.7m;
        decimal time = pay / 3600;
        Console.WriteLine(time); // Prints 579.99325
    }
}


这就是问题:

var payTotal = 2087975.7;


这就是将payTotal分配给double变量。您实际获得的值是2087975.69999999995343387126922607421875,这不是您想要的。每当您发现自己从double转换为decimal或反之亦然时,您应该担心:您在某处使用了错误的类型。货币值应绝对存储在decimal中,而不是在double中(还有其他各种Stack Overflow问题,它们讨论何时使用哪种货币)。

有关更多信息,请参阅我的两篇关于浮点的文章:


Binary floating point in .NET
Decimal floating point in .NET


(一旦获得正确的结果,对它们进行格式化当然是另一回事了,但这应该不会太糟糕...)

09-11 14:06