【问题标题】:How to determine if a decimal/double is an integer?如何确定小数/双精度数是否为整数?
【发布时间】:2011-02-14 15:32:12
【问题描述】:

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

例如:

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)

标签: c#


【解决方案1】:

对于浮点数,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)

【讨论】:

  • 当数字以整数开始时有效,但当数字是某些浮点计算的结果时不一定有效。像“(d % 1)
  • 很遗憾,该线程中的最佳答案是评论,而不是公认的答案。好一个阿德里安。
  • 我也认为阿德里安的上述评论是最好的答案。将他的建议放在正式的 C# 代码中: if (Math.Abs​​(n % 1)
  • 实际上,正如问题所述,这个答案是正确的,而 cmets 是错误的。出于数学目的,OP 不想知道 double 是否是整数,而是想知道如何显示它。只有 exact 整数值应不带小数点显示。此外,关于 mod 不能用于浮点并且不能在 .NET 之外工作的评论也不是很清楚。而(int)d 是一场灾难,大多数双精度值都会抛出异常。
  • double.Epsilon * 100 也不适合。需要将适当的 epsilon 值缩放为要比较的值。 double 中最小的可能变化是值的一小部分,而不是固定数量。他们为 C# double.Epsilon 选择的值也特别糟糕,因为他们使用了与 C 中的 DBL_EPSILON 不同的概念,这种概念已经存在了几十年并且实际上很有用。
【解决方案2】:

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

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

你也可以使用模数。

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

【讨论】:

  • 其中一个会比另一个快吗?我想在性能敏感的环境中执行此操作。
  • @Basil - 视情况而定。你应该为自己做一些计时和判断。
  • Math.Abs(d-(int)d) &lt; double.Epsilond == (int)d 更安全
  • @MathewFoscarini - 我想你很困惑。它将它设置为 false,因为 16.1 - 6.1 的结果不是 int。关键是要查找给定值是否为 int,而不是查找近似于 int 的值是否为 int。
  • @MathewFoscarini - 是的,int 是没有十进制值(或十进制值 0)的数字。 16.1-6.1 不会创建 0 十进制值,它是由 IEEE 浮点格式怪癖引起的非常小的非零值。无法知道该数字是否应该具有十进制值,因此假设舍入值同样不准确。这个问题的目的是知道一个浮点数是否是一个整数,而不是它是否近似一个整数。
【解决方案3】:

这个怎么样?

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);
}

【讨论】:

  • 也许更新您的解决方案并添加: && numberint.MinValue
【解决方案4】:

虽然建议的解决方案似乎适用于简单的示例,但通常这样做是个坏主意。一个数字可能不完全是一个整数,但是当您尝试对其进行格式化时,它与您得到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 听起来很有趣。你有去除尾随零的格式示例吗?
  • 我同意它更安全,并且 OP 应该做什么,但这不是对值是否具有小数部分的更狭窄(但更有趣)问题的答案。跨度>
  • @Clifford:我通常会尝试根据最能解决 OPs 问题的方法来回答,而不是根据标题所说的。标题很少能准确描述问题。
  • +1 同意由于舍入和精度错误,尝试测试浮点数或双精度数以查看它们是否可能是整数是不好的。
  • 对于金钱用途,您可能希望 1.2 显示为 1.20,而建议的解决方案并非如此。有接受者吗?
【解决方案5】:
bool IsInteger(double num) {
    if (ceil(num) == num && floor(num) == num)
        return true;
    else
        return false;
}

问题解决。

编辑:Mark Rushakoff 拥有。

【讨论】:

  • 或者只是return ceil(num) == num &amp;&amp; floor(num) == num;
  • 或只是return ceil(num) == floor(num);
【解决方案6】:
static bool IsWholeNumber(double x) 
{
    return Math.Abs(x % 1) < double.Epsilon;
}

【讨论】:

  • 答案不适用于double x = 0.31d + 0.27d - 0.58d;
【解决方案7】:

Mark Rushakoff 的回答可能更简单,但由于没有隐式除法运算,以下方法也可以工作并且可能更有效:

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

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

如果您想要两种类型的单个表达式,也许

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

【讨论】:

    【解决方案8】:

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

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

    【讨论】:

    • 第一次测试,然后像这样强制转换它会抛出一个异常而不是返回 false,也许更新你的答案
    • @computer,是的,好点。关于投掷,我想这取决于您的项目设置。
    【解决方案9】:

    您可以对 double 类型使用字符串格式。这是一个例子:

    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"
    

    如果这没有帮助,请告诉我。

    【讨论】:

    • 这并没有真正解决确定一个值是否没有小数部分的问题,这是一个数学问题。然而,鉴于他的解释性说明,这可能是 OP 所需要的。
    • 是的,他只想格式化没有小数点的双精度或十进制值。谢谢...
    【解决方案10】:
        public static bool isInteger(decimal n)
        {
            return n - (Int64)n == 0;
        }
    

    【讨论】:

    【解决方案11】:

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

    这是我的代码,如果字符串“s”代表一个最多有两位小数的数字,则返回 true,否则返回 false。它避免了因浮点值不精确而导致的任何问题。

    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-whether-numeric-value-has.html 详细讨论这个问题。

    【讨论】:

    • 这假设您正在使用一种文化。例如,它不适用于表示 1.000,00 等小数的文化
    【解决方案12】:

    使用 int.TryParse 将产生以下结果:

            var shouldBeInt = 3;
    
            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();
    

    【讨论】:

      【解决方案13】:

      您可以简单地将 double 与相同值的 int 转换进行比较。

      double d = 5.0m;
      
      if (d == (int)d)
      {
      .... 
      }
      

      【讨论】:

        【解决方案14】:

        试试这个:

        number == Convert.ToInt16(number);
        

        【讨论】:

          【解决方案15】:

          也许不是最优雅的解决方案,但如果您不太挑剔,它就可以工作!

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

          【讨论】:

          • 这是一个糟糕的解决方案
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-10
          • 2015-04-11
          • 1970-01-01
          • 2020-12-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多