如何确定一个十进制数/双精度浮点数是否为整数?

297

如何判断一个十进制或双精度浮点数是否为整数?

例如:

decimal d = 5.0; // Would be true
decimal f = 5.5; // Would be false
或者
double d = 5.0; // Would be true
double f = 5.5; // Would be false

我想知道这个问题的原因是为了能够以编程方式确定是否要使用.ToString("N0").ToString("N2")输出值。如果没有小数点值,那么我就不想显示它。


Math.Floor(float.Parse(inputValue)) == float.Parse(inputValue) - Murali Murugesan
17个回答

536

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

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

输出:

False
True

更新: 正如@Adrian Lopez在下面提到的,与小值 epsilon 进行比较将丢弃浮点计算错误。由于问题涉及 double 值,因此以下将是一个更具浮点计算证明的答案:

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

113
当数字起始值是整数时,这种方式是有效的,但当数字是某些浮点计算结果时,它可能就不再适用了。那么可以考虑类似于"(d % 1) < epsilon" 的方式,其中epsilon是一个很小的值? - Adrian Lopez
11
这个帖子里最好的答案是一条评论,而不是被接受的答案,真遗憾。干得好,Adrian。 - starskythehutch
14
我认为Adrian在上面的评论中提供的回答是最好的。为了将他的建议转化为正式的C#代码:当(Math.Abs(n % 1) < Double.Epsilon)时,执行某些操作,如果n是整数。 - Ruben Ramirez Padron
10
实际上,根据问题的陈述,这个答案是正确的,而评论是错误的。OP不想知道double是否在数学上是整数,而是想知道如何显示它。只有确切的整数值应该被显示,没有小数点。此外,关于模运算与浮点数无关且不能在.NET之外工作的评论并不了解情况。而(int)d对大多数double值来说都会引发异常,这是一个灾难。 - Jim Balter
3
double.Epsilon * 100也不合适。适当的epsilon值需要根据进行比较的值来进行缩放。Double中最小的可能变化是该值的一小部分,而不是固定的数量。他们为C#选择的double.Epsilon值也特别糟糕,因为他们使用了一个与在C中存在数十年且实际上非常有用的DBL_EPSILON不同的概念。 - tukra
显示剩余9条评论

58

有许多方法可以实现这一点。例如:

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

你也可以使用取模运算。

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

@Basil - 这取决于具体情况。你应该自己进行一些计时并做出判断。 - Erik Funkenbusch
5
Math.Abs(d-(int)d) < double.Epsilond == (int)d 更安全。 - Reactgular
@MathewFoscarini - 你具体指的是“更安全”还是“更准确”? - Erik Funkenbusch
4
@MathewFoscarini - 我认为你有些混淆了。它将其设为false,因为16.1-6.1的结果不是整数。重点是要判断一个给定的值是否为整数,而不是判断接近整数的值是否为整数。 - Erik Funkenbusch
2
@MathewFoscarini - 是的,int是一个没有小数值(或小数值为0)的数字。16.1-6.1并不会产生0小数值,它是由IEEE浮点格式怪异性引起的非常小的非零值。无法知道这个数字是否应该有小数值,因此假设舍入值同样不准确。问题的目的是要知道浮点数是否为整数,而不是是否近似于整数。 - Erik Funkenbusch
显示剩余6条评论

26

这个怎么样?

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

使用相同的代码来处理 decimal 类型。

Mark Byers说得不错,实际上这可能不是你真正想要的。如果你真正在意的是将一个数字四舍五入到最接近的两个小数位后是否为整数,那么你可以改用以下方式:

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

1
也许您可以更新您的解决方案并添加:&& number<int.MaxValue && number>int.MinValue - Walter Verhoeven

13
bool IsInteger(double num) {
    if (ceil(num) == num && floor(num) == num)
        return true;
    else
        return false;
}

问题已解决。

编辑:被Mark Rushakoff击败了。


4
或者只需返回 ceil(num) == num && floor(num) == num;。该语句的意思是判断变量 num 是否为整数。 - Brian Rasmussen
21
或者只需返回 ceil(num) == floor(num);这意味着将输入的数字取整后,其上下取整结果相等,则返回真。 - gregsdennis

13

虽然提出的解决方案似乎适用于简单的示例,但总体而言这样做是不好的。一个数字可能并不完全是整数,但当你尝试格式化它时,它足够接近整数,以至于你获得了1.000000。如果你进行理论上应该得到1的计算,但实际上由于舍入误差导致得到一个非常接近但不完全等于1的数字,就会发生这种情况。

相反,先格式化它,如果你的字符串以点和零结尾,则删除它们。还有一些格式可以自动去除尾随的零。这对你的目的可能已经足够好了。

double d = 1.0002;
Console.WriteLine(d.ToString("0.##"));
d = 1.02;
Console.WriteLine(d.ToString("0.##"));

输出:

1
1.02

@Mark 听起来很有趣。你有一个去除尾随零的格式示例吗? - Jim Geurts
3
@Clifford: 我通常尝试根据最佳解决方法回答问题,而不是根据标题所说的回答。标题很少是问题的准确描述。 - Mark Byers
1
对于货币使用,您可能希望将1.2显示为1.20,但这并不是建议解决方案的情况。有人愿意接受吗? - Kjell Rilbe
For money, d.ToString("0.00") - PRMan
或者更好的方法是使用 d.ToString("C") 来处理货币 - 如果你正在处理货币,你可能不想使用 double,而是使用具有固定精度的 decimal。 - herostwist
显示剩余2条评论

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

2
答案对于 double x = 0.31d + 0.27d - 0.58d; 不起作用。 - YantingChen


4

Mark Rushakoff的答案可能更简单,但以下方法也可行并且效率可能更高,因为没有隐式除法操作:

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

并且

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

如果你想要一个适用于两种类型的表达式,也许可以这样:
     bool isInteger = (double)((int)val) == (double)val ;

3
如果 Int32 的上下限很重要:
public bool IsInt32(double value)
{
    return  value >= int.MinValue && value <= int.MaxValue && value == (int)value;
}

先进行测试,然后像这样转换,它会抛出异常而不是返回false,也许你需要更新你的答案。 - Walter Verhoeven
@电脑,是的,说得好。关于强制转换时抛出异常,我想这取决于你的项目设置。 - nawfal

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

这个答案和这个回答有什么不同? - xskxzr

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