双精度数据类型,计算小数点后的位数

6

以下方法应该返回一个答案,指这个(双精度)值有多少位小数。当值看起来像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等

问题:
我该如何解决这个问题?如果使用double类型无法实现此方法,还有其他方法吗?

[编辑]
- 对问题进行了微小的文本更改,
- 由于“小数位数”意义的误用,进行了语言修正。


99,09是一个打字错误吗?应该是99.09对吧? - CB.
1
@Christian,是打字错误还是文化差异? - Independent
2
我理解你的业务需求是要确定所提供值的精度(小数点后位数)。我们试图告诉你的是,从编程角度来看,这是无法确定的。你可以确定的是一个双精度浮点数字符串表示中分数部分包含多少个字符。如果不将其转换为字符串,你将无法得到想要的结果,因为我可以给你几乎无限数量的值,它们在数学上都是相等的,并且回答你的问题会有不同的结果。 - Rick Liddle
@Rick,感谢你的帮助(十进制精度)。这个问题对我的业务目的很重要。我如何将数字转换为字符串并保留小数位数(即使是0)? - Independent
Jonas,你正在处理的数值是否总是使用“.”作为小数分隔符,还是需要考虑不同文化对于小数的书写方式? - Rick Liddle
显示剩余12条评论
4个回答

5

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

与 @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的字符串表示不同。输出的第一行就显示了这一点:59005900.00 - Rick Liddle
谢谢。这真是一个不错的示例。然而,令我惊讶的是,.NET CAN 给我一个(double)5900.00(即使在VS智能感知/快速查看中!),但我们无法用.NET代码捕捉它。 - Independent

2
这不是被问及的内容,但却是我所需的。也许会对某人有所帮助:
 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

2

您正在考虑 double 的字符串表示。例如,double 不会区分以下内容:

123
123.0
123.000000

这个双精度浮点数是一样的,你得到多少位小数,实际上取决于你的字符串格式选项(或者默认设置)。你可以将双精度浮点数格式化为带有很多小数位的字符串,然后去掉所有尾随零,再计算小数位数。


谢谢,但抱歉 - 去掉所有尾随零只会返回0吗?这种格式真的非常严格定义。这种格式是不可争议的。如果双精度浮点数为356.00,则必须返回2。如果双精度浮点数为356.09,则也应返回2。 - Independent
如果您将356.00解析为双精度浮点数,它将“丢失”关于.00的信息。356.00只是双精度值的(十进制)字符串表示,因此确定356.00的小数位没有实际意义。如果您将参数作为字符串传递,则可以计算小数位。但是,如果将双精度浮点数转换为字符串,则这没有意义,因为每次这样做时,您都已经指定了(显式地或通过默认值或当前文化隐式地)要求多少小数位数。 - Marian Theisen
我可能迷失了方向,但如果参数传递了“356.00”的值,则方法返回2是最重要的。这就是我所描述的问题的一部分,为什么我需要另一种解决方案而不是ToString。 - Independent
该方法的目的是回答“这个(double)值有多少位小数?”的提问者。 - Independent
我向你道歉,因为你的回答是正确的,但是这是基于我的问题错误。我错误地要求小数位数,而我实际上是要求小数(小数点后没有整数)。然而,即使经过这一切,我仍然无法得到帮助。 - Independent

2
创建一个接收字符串而非双精度浮点数的方法:
    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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接