【问题标题】:Double datatype, count decimals after decimal-place双数据类型,小数点后计算小数
【发布时间】:2011-09-08 10:11:35
【问题描述】:

下面的方法应该返回“什么小数精度,尾随数字的数量,这个(双)值有什么?”的答案。当值看起来像 5900.43、5900.043 等等时,我做对了。当该方法收到 5900.00 时,它返回 0,这是错误的(在我的需要中)。

   /// <summary>
   /// Return count of decimals after decimal-place 
   /// </summary>
   private int getDecimalCount(double val)
   {
        int count = 0;
        ...
        return count;
   }

当参数“val”为(此方法的正常值样本)时

5900.00 返回 2
5900.09 返回 2
5900.000 返回 3
5900.001 返回 3
1.0 返回 1
0.0000005 返回 7
1.0000000 返回 7
5900822 返回 0

我的问题是计算 .0 .00 .000 等等

问题:
我该如何解决这个问题?如果这种方法不能用于双打,还有什么办法?

[已编辑]
- 对文本进行细微更改以提出更清晰的问题,
- 由于“小数位”的误用含义而导致的语言更正

【问题讨论】:

  • 如果您提供更多关于您想要实现的目标的详细信息,将会有所帮助。例如,对于值 (1.0D + Double.Epsilon) = (1.0D + 4.94065645841247e-324),您希望看到什么?
  • 99,09 是错字吗?会是 99.09 正确吗?
  • @Christian,错字或文化差异,
  • @Joe 该方法必须返回正确的小数位数。到目前为止,我看到/尝试过的转换似乎无法理解小数位只有零的情况。
  • 我了解您的业务需要确定所提供值的精度(小数位数)。我们都想告诉您的是,从程序化的角度来看,这是无法确定的。您可以确定的是字符串表示的双精度浮点数的小数部分中存在多少个字符。如果不转换为字符串,您将无法执行所需的操作,因为我可以为您提供几乎无限数量的值,这些值在数学上彼此相等,并且都以不同的方式回答您的问题。

标签: c#


【解决方案1】:

编辑:更新以简化不同文化的处理。

与@Miguel 类似,这就是我的处理方式:

public static int getDecimalCount(double dVal, string sVal, string culture)
{
    CultureInfo info = CultureInfo.GetCultureInfo(culture);

    //Get the double value of the string representation, keeping culture in mind
    double test = Convert.ToDouble(sVal, info);

    //Get the decimal separator the specified culture
    char[] sep = info.NumberFormat.NumberDecimalSeparator.ToCharArray();

    //Check to see if the culture-adjusted string is equal to the double
    if (dVal != test)
    {
        //The string conversion isn't correct, so throw an exception
        throw new System.ArgumentException("dVal doesn't equal sVal for the specified culture");
    }

    //Split the string on the separator 
    string[] segments = sVal.Split(sep);

    switch (segments.Length)
    {
        //Only one segment, so there was not fractional value - return 0
        case 1:
            return 0;
        //Two segments, so return the length of the second segment
        case 2:
            return segments[1].Length;

        //More than two segments means it's invalid, so throw an exception
        default:
            throw new Exception("Something bad happened!");
    }
}

还有一个美式英语的捷径:

public static int getDecimalCount(double dVal, string sVal)
{
    return getDecimalCount(dVal, sVal, "en-US");
}

测试:

static void Main(string[] args)
{
    int i = 0;

    double d = 5900.00; 
    string s = "5900.00";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 2. Actual output: {0}", i);
    Console.WriteLine();

    d = 5900.09;
    s = "5900.09";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 2. Actual output: {0}", i);
    Console.WriteLine();

    d = 5900.000;
    s = "5900.000";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 3. Actual output: {0}", i);
    Console.WriteLine();

    d = 5900.001;
    s = "5900.001";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 3. Actual output: {0}", i);
    Console.WriteLine();

    d = 1.0; 
    s = "1.0";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 1. Actual output: {0}", i);
    Console.WriteLine();

    d = 0.0000005; 
    s = "0.0000005";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 7. Actual output: {0}", i);
    Console.WriteLine();

    d = 1.0000000; 
    s = "1.0000000";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 7. Actual output: {0}", i);
    Console.WriteLine();

    d = 5900822; 
    s = "5900822";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 0. Actual output: {0}", i);

    Console.ReadLine();
}

最后是测试的输出:

使用 dVal = 5900 和 sVal = 5900.00 进行测试。 预期输出:2。实际输出:2

使用 dVal = 5900.09 和 sVal = 5900.09 进行测试。 预期输出:2。实际输出:2

使用 dVal = 5900 和 sVal = 5900.000 进行测试。 预期输出:3。实际输出:3

使用 dVal = 5900.001 和 sVal = 5900.001 进行测试。 预期输出:3。实际输出:3

使用 dVal = 1 和 sVal = 1.0 进行测试。 预期输出:1。实际输出:1

使用 dVal = 5E-07 和 sVal = 0.0000005 进行测试。 预期输出:7。实际输出:7

使用 dVal = 1 和 sVal = 1.0000000 进行测试。 预期输出:7。实际输出:7

使用 dVal = 5900822 和 sVal = 5900822 进行测试。 预期输出:0。实际输出:0

如果您对此有任何疑问或没有意义,请告诉我。

【讨论】:

  • 您可以从上面的输出中看到为什么我们提出了我们早期所做的问题。 .NET Framework 对待 double 值的方式与处理 double 的字符串表示的方式不同。输出的第一行显示:5900 vs. 5900.00
  • 谢谢。这真是一个整洁的样本。然而,.NET CAN 给了我一个(双)5900.00(甚至是 VS intellisense/quickwatch!),而我们无法用 .NET 代码获取它,这让我感到非常惊讶。
【解决方案2】:

您正在考虑双精度的字符串表示。例如,双精度在这些之间没有区别:

123
123.0
123.000000

这都是相同的双精度数,您得到多少小数位,实际上取决于您的字符串格式选项(或默认设置)。您可以做的是将您的双打格式化为带有很多小数位的字符串,然后去除所有尾随零,然后计算小数位。

【讨论】:

  • 谢谢,但很抱歉 - 去掉所有尾随零只会..返回 0?这种格式的定义非常明确。格式没有争议。如果双精度是 356.00,它必须返回 2。如果双精度是 356.09,它也应该返回 2。
  • 如果您将 356.00 解析为双精度,它将“松散”有关 .00 的信息,356.00 只是双精度值的(十进制)字符串表示,因此实际上没有意义确定 356.00 的小数位,当它是双精度时。如果您将参数作为字符串传递,那么您可以计算小数。但是,如果将双精度数转换为字符串,则没有任何意义,因为每次这样做时,您已经指定(显式地或通过默认值或当前文化隐式地)您想要多少个小数。
  • 我可能在这里迷路了,但是如果参数传递了“356.00”的值,该方法返回 2 是可能的最高权重。那就是我描述的问题的一部分,为什么我需要另一个解决方案,然后是 ToString,
  • 该方法的目的是回答“这个(双)值有多少个小数?”。
  • 我向您致歉,因为您回答正确 - 但基于我的问题中的错误。我被错误地要求小数位”,而我的意思是要求小数位(小数位后没有整数)。但是在这一切之后我仍然没有帮助。
【解决方案3】:

创建一个接收字符串而不是双精度的方法:

    public int CountDecimalDigits(string value)
    {
        char[] possibleChars = "0123456789.".ToCharArray();
        int decimalPoints = 0;
        foreach (char ch in value)
        {
            if (Array.IndexOf(possibleChars, ch) < 0)
                throw new Exception();
            if (ch == '.') decimalPoints++;
        }
        if (decimalPoints > 1)
            throw new Exception();
        if (decimalPoints == 0) return 0;
        return value.Length - value.IndexOf('.') - 1;
    }

【讨论】:

    【解决方案4】:

    这不是被要求的,但这是我需要的。也许它会帮助某人:

     private static int getDecimalCount(double val)
     {
         int i=0;
         while (Math.Round(val, i) != val)
             i++;
         return i;
     }
    double val1 = 5900.00; int count1 = getDecimalCount(val1);//result: 0
    double val2 = 5900.09; int count2 = getDecimalCount(val2);//result: 2
    double val3 = 5900.000; int count3 = getDecimalCount(val3);//result: 0
    double val4 = 1.0; int count4 = getDecimalCount(val4);//result: 0
    double val5 = 0.0000005; int count5 = getDecimalCount(val5);//result: 7
    double val6 = 1.0000000; int count6 = getDecimalCount(val6);//result: 0
    double val7 = 5900822; int count7 = getDecimalCount(val7);//result: 0
    
    double val9 = 4.5565d; int count9 = getDecimalCount(val9);//result: 4
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-16
      • 2021-11-19
      • 1970-01-01
      • 2023-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-07
      相关资源
      最近更新 更多