10

好吧,“为了钱,总是十进制”的规则在 Microsoft 开发团队内部并不适用,因为如果它是:

Namespace: Microsoft.VisualBasic
Assembly:  Microsoft.VisualBasic (in Microsoft.VisualBasic.dll)

Financial.IPmt并且所有其他方法都将接收/返回decimal,而不是double按原样接收/返回。

现在我想知道我是否可以使用这些方法而不必担心出现回合错误?

我应该使用其他一些图书馆来处理财务问题吗?如果是的话,你能指点我一些好的(供C#使用)吗?

4

3 回答 3

10

这是关于这个主题的有趣讨论:http ://www.vbforums.com/showthread.php?t=524101

大约 1/3 的人解释说它使用 Double 因为 VB.NET 函数的实现与 VB6 完全相同。VB6 没有十进制类型,这就是它使用双精度的原因。

因此,如果准确性很重要,您似乎不应该使用这些功能。

这个问题的答案有一些有希望的替代方案 - 只需忽略建议使用 VB 库的公认答案。

之前链接的问题已被删除,所以这里是我参考的一些建议(注意:我没有尝试过这些,YMMV)

于 2010-04-08T23:02:05.407 回答
10

用于货币的规则decimal很有帮助,因为大多数货币都有十进制单位。通过使用十进制算术,您可以避免引入和累积舍入误差。

金融类函数使用浮点数有几个原因:

  • 它们不会在内部累积——它们基于封闭形式的指数/对数计算,而不是周期内的迭代和求和。
  • 他们倾向于不使用或产生精确的十进制值。例如,一个精确的小数年利率除以 12 个月的付款就变成了一个重复小数。
  • 它们主要用于决策支持,最终对实际簿记几乎没有适用性。

Pmt并且四舍五入可以确定名义上的每月付款,但是一旦确定了该金额,余额累积 - 已付款,应用的利息费用等 - 发生在decimal. 此外,延迟付款或预付款、付款假期和其他此类不统一将使财务职能提供的预计摊销无效。

于 2010-04-09T00:11:48.267 回答
4

你可以使用这个类:

public class Financial
{
    #region Methods

    public static decimal IPmt(decimal Rate, decimal Per, decimal NPer, decimal PV, decimal FV, FinancialEnumDueDate Due)
    {
        decimal num;
        if (Due != FinancialEnumDueDate.EndOfPeriod)
        {
            num = 2;
        }
        else
        {
            num = 1;
        }
        if ((Per <= 0) || (Per >= (NPer + 1)))
        {
            //Argument_InvalidValue1=

            throw new ArgumentException("Argument 'Per' is not a valid value.");
        }
        if ((Due != FinancialEnumDueDate.EndOfPeriod) && (Per == 1))
        {
            return 0;
        }
        decimal pmt = Pmt(Rate, NPer, PV, FV, Due);
        if (Due != FinancialEnumDueDate.EndOfPeriod)
        {
            PV += pmt;
        }
        return (FV_Internal(Rate, Per - num, pmt, PV, FinancialEnumDueDate.EndOfPeriod) * Rate);
    }

    public static decimal PPmt(decimal Rate, decimal Per, decimal NPer, decimal PV, decimal FV, FinancialEnumDueDate Due)
    {
        if ((Per <= 0) || (Per >= (NPer + 1)))
        {
            throw new ArgumentException("Argument 'Per' is not valid.");
        }
        decimal num2 = Pmt(Rate, NPer, PV, FV, Due);
        decimal num = IPmt(Rate, Per, NPer, PV, FV, Due);
        return (num2 - num);
    }

    static decimal FV_Internal(decimal Rate, decimal NPer, decimal Pmt, decimal PV, FinancialEnumDueDate Due)
    {
        decimal num;
        if (Rate == 0)
        {
            return (-PV - (Pmt * NPer));
        }
        if (Due != FinancialEnumDueDate.EndOfPeriod)
        {
            num = 1 + Rate;
        }
        else
        {
            num = 1;
        }
        decimal x = 1 + Rate;
        decimal num2 = (decimal)Math.Pow((double)x, (double)NPer);
        return ((-PV * num2) - (((Pmt / Rate) * num) * (num2 - 1)));
    }

    static decimal Pmt(decimal Rate, decimal NPer, decimal PV, decimal FV, FinancialEnumDueDate Due)
    {
        decimal num;
        if (NPer == 0)
        {
            throw new ArgumentException("Argument NPer is not a valid value.");
        }
        if (Rate == 0)
        {
            return ((-FV - PV) / NPer);
        }
        if (Due != FinancialEnumDueDate.EndOfPeriod)
        {
            num = 1 + Rate;
        }
        else
        {
            num = 1;
        }
        decimal x = Rate + 1;
        decimal num2 = (decimal)Math.Pow((double)x, (double)NPer);
        return (((-FV - (PV * num2)) / (num * (num2 - 1))) * Rate);
    }

    #endregion Methods
}
于 2010-07-20T13:21:43.257 回答