【问题标题】:Performing Math operations on decimal datatype in C#?在 C# 中对十进制数据类型执行数学运算?
【发布时间】:2011-05-06 16:02:52
【问题描述】:

我想知道以上是否有可能。例如:

Math.Sqrt(myVariableHere);

在查看重载时,它需要一个双参数,所以我不确定是否有另一种方法可以使用十进制数据类型来复制它。

【问题讨论】:

    标签: c# math types double decimal


    【解决方案1】:

    我不明白为什么这个问题的所有答案都是一样的。

    有几种方法可以根据数字计算平方根。其中之一是由艾萨克牛顿提出的。我只会写这个方法最简单的实现之一。我用它来提高双精度平方根的精度。

    // x - a number, from which we need to calculate the square root
    // epsilon - an accuracy of calculation of the root from our number.
    // The result of the calculations will differ from an actual value
    // of the root on less than epslion.
    public static decimal Sqrt(decimal x, decimal epsilon = 0.0M)
    {
        if (x < 0) throw new OverflowException("Cannot calculate square root from a negative number");
    
        decimal current = (decimal)Math.Sqrt((double)x), previous;
        do
        {
            previous = current;
            if (previous == 0.0M) return 0;
            current = (previous + x / previous) / 2;
        }
        while (Math.Abs(previous - current) > epsilon);
        return current;
    }
    

    关于速度:在最坏的情况下(epsilon = 0 并且数字是 decimal.MaxValue)循环重复不到 3 次。

    如果您想了解更多信息,请阅读this (Hacker's Delight by Henry S. Warren, Jr.)

    【讨论】:

      【解决方案2】:

      我刚遇到这个问题,我建议使用与 SLenik 提出的算法不同的算法。这是基于Babylonian Method

      public static decimal Sqrt(decimal x, decimal? guess = null)
      {
          var ourGuess = guess.GetValueOrDefault(x / 2m);
          var result = x / ourGuess;
          var average = (ourGuess + result) / 2m;
      
          if (average == ourGuess) // This checks for the maximum precision possible with a decimal.
              return average;
          else
              return Sqrt(x, average);
      }
      

      它不需要使用现有的Sqrt 函数,因此避免了转换为double 并返回,随之而来的精度损失。

      【讨论】:

      • Bobson,您提出了另一种可能的解决方案,但 SLenik 的解决方案没有缺陷,因为他只使用 double Sqrt(double) 作为起点——就像种子一样。然后,在循环中,他使用全精度小数 x 来调整 Sqrt 的结果值。
      • @farfareast - 这是一个有效的观点,在大多数情况下,精度问题并不重要。但如果你一开始就有一个非常精确的小数,你会丢失其中的一部分,这可能会导致结果略有偏差。我还发现使用平方根计算平方根在哲学上是令人反感的,尽管如果我确实需要它并且出于性能原因这样做,那肯定不会阻止我编写代码。
      • 另外,在我的初始测试(和发布)中,我的算法似乎快了 100 倍,但在进一步测试后,我发现我进行测试的顺序会影响结果,所以我删除了那部分。它仍然是一个有效的算法,而且我认为它稍微快一些,但这只是一个很小的区别。 Sqrt 的内置 double 版本仍然比两者都快。
      • 难怪双 sqrt 更快。看看这个wikipedia article 的引用:Floating point instructions x86 assembly language includes instructions for a stack-based floating point unit. They include addition, subtraction, negation, multiplication, division, remainder, square roots, integer truncation, fraction truncation, and scale by power of two. 特别是在英特尔机器代码指令集中有 FSQRT 指令。 :-) 另见:here
      • 我认为这是一个非常棒的解决方案。谢谢。
      【解决方案3】:
      Math.Sqrt((double)myVariableHere);
      

      将返回一个双精度值,即 decimal myVariableHere 的平方根。

      【讨论】:

        【解决方案4】:

        简单:将您的decimal 转换为double 并调用函数,获取结果并将其转换回decimal。这可能会比您自己制作的任何 sqrt 函数更快,并且可以节省大量精力。

        【讨论】:

          【解决方案5】:

          在大多数涉及decimal(货币等)的情况下,扎根有用;并且根不会具有您可能期望 decimal 具有的预期精度。您当然可以通过强制转换来强制它(假设我们没有处理 decimal 范围的极端):

          decimal root = (decimal)Math.Sqrt((double)myVariableHere);
          

          这迫使您至少承认固有的舍入问题。

          【讨论】:

          • 好吧,我正在制作一个应用程序计算黄金分割率,最终将进入小数范围。在我的场景中不起作用。
          猜你喜欢
          • 2012-12-07
          • 2017-04-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-12
          • 1970-01-01
          • 2023-03-04
          • 2011-05-02
          • 1970-01-01
          相关资源
          最近更新 更多