【问题标题】:Finding the number of places after the decimal point of a Double查找 Double 小数点后的位数
【发布时间】:2012-02-21 22:58:36
【问题描述】:

我有一个 Double 值:

double a = 4.5565;

计算小数点后位数(本例中为 4)的最简单方法是什么。

我知道我可以转换为字符串并进行拆分并获取长度。但是有没有更简单的方法?

【问题讨论】:

  • “更容易”是什么意思?我怀疑从写作/阅读的角度来看有什么更容易的,但例如在 CPU 操作方面可能会更容易。
  • a 的值可能不完全是 4.5565。如果您不明白为什么,我建议您阅读以下内容:csharpindepth.com/Articles/General/FloatingPoint.aspx
  • 这取决于,你想数什么样的小数?会出现在 C# 的 ToString 中的那些?代表真正准确性的那些?或者所有这些都将出现在价值的完整基数 10 转换中?
  • 请注意,Decimal 可以这样做。

标签: c#


【解决方案1】:

没有简单的方法,特别是因为从数学上讲,数字的数量可能远远超过显示的数量。例如,4.5565 实际上存储为4.556499999999999772626324556767940521240234375(感谢harold 计算)。您不太可能找到解决此问题的有用方法。

编辑

可以想出一些像这样工作的算法:如果在计算十进制表示时,你连续找到一定数量的 9(或零),你四舍五入(或下)到一系列 9(或零)开始之前的最后一个位置。我怀疑你会在这条路上遇到比你预想的更多的麻烦。

【讨论】:

  • @phoog 我同意你所说的,但你对我的回答有什么看法?
  • @DorCohen 我现在没有时间深入研究您的答案。今晚晚些时候或明天早上我会试着看看。
  • 上一条评论不小心变成了32bit float,应该是:4.556499999999999772626324556767940521240234375
  • @phoog 我在哪里可以了解为什么它被存储为 4.556499999999999772626324556767940521240234375
  • @blitzkriegz 其他人在 cmets 中就您的问题提出的链接是对 IEEE 浮点系统的很好讨论。我认为没有必要添加它们。简短的回答是二进制表示是以 2 为底的,并且有许多以 10 为底的有限小数但以 2 为底的无限小数的值;这些必须被截断(类似于 0.3333333 是 1/3 的截断十进制近似值)。 harold 计算的数字是值 4.5565 的不精确二进制近似值的精确十进制表示。
【解决方案2】:
var precision = 0;
var x = 1.345678901m;

while (x*(decimal)Math.Pow(10,precision) != 
         Math.Round(x*(decimal)Math.Pow(10,precision))) 
   precision++;

precision 将等于十进制值的有效位数(将 x 设置为 1.23456000 将导致精度为 5,即使最初在文字中指定了 8 位)。这在与小数位数成比例的时间内执行。它只计算小数位数;您可以通过取 Math.Log10(x) 的整数部分来计算小数点左侧的位数。它最适用于小数,因为它们具有更好的值精度,因此舍入误差更小。

【讨论】:

    【解决方案3】:

    写一个函数

    int CountDigitsAfterDecimal(double value)
            {
                bool start = false;
                int count = 0;
                foreach (var s in value.ToString())
                {
                    if (s == '.')
                    {
                        start = true;
                    }
                    else if (start)
                    {
                        count++;
                    }
                }
    
                return count;
            }
    

    【讨论】:

    • 这不适用于以标准格式(例如 5.821E+12)表示的数字,因为小数点总是排在第二位。在给出的示例中,结果实际上应该是 0,因为 5.821E+12 是一个非常大的整数。
    • 另外一个考虑是有些文化不使用'.'作为小数点分隔符,因此您的“ToString()”应该被赋予“CultureInfo.InvariantCulture”。
    【解决方案4】:

    我认为字符串解决方案是最好的:((a-(int)a)+"").length-2

    【讨论】:

    • 而不是拆分,您只是不计算字符串中的0.。与闪电战的解决方案没有太大区别
    • 添加 "" 是调用ToString() 的真正可怕的替代方法。
    • @JonSkeet 为什么会这样?如果对象为空,它总是会在 toString 可能失败的地方工作(当然在这种情况下 a 是原始的)。
    • 就个人而言,我不希望看到这一点,因为它混淆了代码的意图。当您看到 ToString() 调用时,您就知道编码器试图做什么,并且通常不难找到字符串转换的实现。字符串连接剥夺了意图,需要更多的知识和时间来弄清楚会发生什么。这种方式太“聪明”了(聪明的代码不利于可维护性)。
    • 好主意,但您还应该检查“a”是否为负数。
    【解决方案5】:

    基于詹姆斯的答案更清晰:

    int num = dValue.ToString().Length - (((int)dValue).ToString().Length + 1);
    

    num 是小数点后的确切位数。 不包括 0 这样的(25.520000) 在这种情况下,您将得到 num= 2

    【讨论】:

      【解决方案6】:

      我认为这可能是一个解决方案:

       private static int getDecimalCount(double val)
       {
           int i=0;
           while (Math.Round(val, i) != val)
               i++;
           return i;
       }
      
      double val9 = 4.5565d; int count9 = getDecimalCount(val9);//result: 4
      

      抱歉重复 -> https://stackoverflow.com/a/35238462/1266873

      【讨论】:

        【解决方案7】:

        如果需要,我可能会使用此代码,

        myDoubleNumber.ToString("R").Split('.')[1].Length
        

        "R"这里是Round Trip Format Specifier

        当然,我们首先需要检查索引边界。

        【讨论】:

        • @batsheva 就像我说的,首先检查数组索引范围
        【解决方案8】:

        另一种解决方案是使用一些字符串函数:

        private int GetSignificantDecimalPlaces(decimal number, bool trimTrailingZeros = true)
        {
          string stemp = Convert.ToString(number);
        
          if (trimTrailingZeros)
            stemp = stemp.TrimEnd('0');
        
          return stemp.Length - 1 - stemp.IndexOf(
             Application.CurrentCulture.NumberFormat.NumberDecimalSeparator);
        }
        

        记得使用 System.Windows.Forms 来访问 Application.CurrentCulture

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-25
          • 2014-06-10
          • 1970-01-01
          • 1970-01-01
          • 2018-09-18
          • 2011-11-14
          • 2011-02-18
          • 2017-02-24
          相关资源
          最近更新 更多