关于c#:如何确定decimal / double是否为整数?


How to determine if a decimal/double is an integer?

如何判断一个十进制或双精度值是一个整数?

例如:

1
2
decimal d = 5.0; // Would be true
decimal f = 5.5; // Would be false

1
2
double d = 5.0; // Would be true
double f = 5.5; // Would be false

我之所以想知道这一点,是因为我可以通过编程确定是否要使用.ToString("N0").ToString("N2")输出值。如果没有小数点,那么我不想显示它。


对于浮点数,n % 1 == 0通常是检查是否有超过小数点的内容的方法。

1
2
3
4
5
6
7
public static void Main (string[] args)
{
    decimal d = 3.1M;
    Console.WriteLine((d % 1) == 0);
    d = 3.0M;
    Console.WriteLine((d % 1) == 0);
}

输出:

1
2
False
True

更新:正如下面提到的@adrian lopez,与一个小值epsilon比较将丢弃浮点计算的错误计算。由于问题是关于double值,下面将是一个更为浮点计算证明的答案:

1
Math.Abs(d % 1) <= (Double.Epsilon * 100)


有很多方法可以做到这一点。例如:

1
2
double d = 5.0;
bool isInt = d == (int)d;

您也可以使用modulo。

1
2
double d = 5.0;
bool isInt = d % 1 == 0;


这个怎么样?

1
2
3
public static bool IsInteger(double number) {
    return number == Math.Truncate(number);
}

同一代码用于decimal

马克·拜尔斯说得很好,事实上:这可能不是你真正想要的。如果您真正关心的是一个四舍五入到小数点后两位的数字是否为整数,您可以这样做:

1
2
3
public static bool IsNearlyInteger(double number) {
    return Math.Round(number, 2) == Math.Round(number);
}


虽然所提出的解决方案似乎适用于简单的例子,但一般来说,这样做是一个坏主意。一个数字可能不是一个整数,但当您试图格式化它时,它已经足够接近一个整数,您可以得到1.000000。如果你做一个理论上应该精确到1的计算,就会发生这种情况,但实际上由于舍入误差,会给出一个非常接近但不完全等于1的数字。

相反,首先格式化它,如果字符串以一个后跟零的句点结束,那么去掉它们。还有一些格式,您可以使用该条带自动尾随零。这对你来说也许足够好。

1
2
3
4
double d = 1.0002;
Console.WriteLine(d.ToString("0.##"));
d = 1.02;
Console.WriteLine(d.ToString("0.##"));

输出:

1
2
1
1.02


1
2
3
4
5
6
bool IsInteger(double num) {
    if (ceil(num) == num && floor(num) == num)
        return true;
    else
        return false;
}

问题解答

编辑:马克·拉沙科夫编辑。


如果Int32的上界和下界很重要:

1
2
3
4
public bool IsInt32(double value)
{
    return  value >= int.MinValue && value <= int.MaxValue && value == (int)value;
}


1
2
3
4
static bool IsWholeNumber(double x)
{
    return Math.Abs(x % 1) < double.Epsilon;
}

Mark Rushakoff的回答可能更简单,但由于没有隐式的除法运算,因此以下内容也有效,而且效率可能更高:

1
     bool isInteger = (double)((int)f) == f ;

1
     bool isInteger = (decimal)((int)d) == d ;

如果两种类型都需要一个表达式,也许

1
     bool isInteger = (double)((int)val) == (double)val ;

您可以对双精度类型使用字符串格式。下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
double val = 58.6547;
String.Format("{0:0.##}", val);      
//Output:"58.65"

double val = 58.6;
String.Format("{0:0.##}", val);      
//Output:"58.6"

double val = 58.0;
String.Format("{0:0.##}", val);      
//Output:"58"

如果这不起作用,请告诉我。


1
2
3
4
    public static bool isInteger(decimal n)
    {
        return n - (Int64)n == 0;
    }


使用Int.Tryparse将产生以下结果:var应等于3;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        var shouldntBeInt = 3.1415;

        var iDontWantThisToBeInt = 3.000f;

        Console.WriteLine(int.TryParse(shouldBeInt.ToString(), out int parser)); // true

        Console.WriteLine(int.TryParse(shouldntBeInt.ToString(), out parser)); // false

        Console.WriteLine(int.TryParse(iDontWantThisToBeInt.ToString(), out parser)); // true, even if I don't want this to be int

        Console.WriteLine(int.TryParse("3.1415", out  parser)); // false

        Console.WriteLine(int.TryParse("3.0000", out parser)); // false

        Console.WriteLine(int.TryParse("3", out parser)); // true

        Console.ReadKey();


我也遇到过类似的情况,但是值是字符串。用户输入的值应该是一个美元金额,所以我想验证它是否是数字,并且最多有两个小数位。

下面是我的代码,如果字符串"s"表示最多有两位小数的数字,则返回true,否则返回false。它避免了由于浮点值不精确而导致的任何问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try
{
    // must be numeric value
    double d = double.Parse(s);
    // max of two decimal places
    if (s.IndexOf(".") >= 0)
    {
        if (s.Length > s.IndexOf(".") + 3)
            return false;
    }
    return true;
catch
{
    return false;
}

我在http://progblog10.blogspot.com/2011/04/determining-if-numeric-value-has.html上更详细地讨论了这个问题。


试试这个:

1
number == Convert.ToInt16(number);

你可以使用"台盼色"方法。

1
int.TryParse()

这将检查该值是否可以转换为整数整数值。然后,结果可以指示一个标志,该标志可以在代码中的其他地方使用。


也许不是最优雅的解决方案,但如果你不太挑剔,它是有效的!

1
2
3
bool IsInteger(double num) {
    return !num.ToString("0.################").Contains(".");
}