【问题标题】:How do I determine whether the value of a float is a whole number? [duplicate]如何确定浮点数的值是否为整数? [复制]
【发布时间】:2014-10-06 02:40:15
【问题描述】:

我有一个程序,如果是浮点数,我需要打印 FLOAT,如果是常规数字,我需要打印 INTEGER。

示例伪代码

float num = 1.5; 
if (num mod sizeof(int)==0)
  printf ("INTEGER");
else
  printf("FLOAT");

例如:

  • 1.6 将打印“FLOAT”
  • 1.0 将打印“INTEGER”

这样的事情会起作用吗?

【问题讨论】:

  • 你是在宏中尝试这个吗?否则,类型总是已知的。
  • 使用sizeof 肯定会不起作用。您需要提供一个更大的示例来说明您如何尝试使用它。否则,真的不清楚为什么你只是不知道它是浮点数还是整数。
  • 代替伪代码,请说明您打算如何在 readl 代码中使用它。因为它在具有静态变量类型的语言中没有真正意义。
  • 你是不是要区分变量类型?还是只是某些价值观?
  • 您的问题真的是“如何确定float 的值是否为整数?”?

标签: c


【解决方案1】:

这样的东西会起作用吗?

没有。例如在 x86_32 和 ARM 32 位架构 sizeof(int) == 4sizeof(float) == 4

无论您认为mod 是什么,它都清楚地表明您不了解sizeof 运算符的作用。

【讨论】:

  • 如果C11是一个选项,可以使用_Generic
  • 你会回答标题中的问题吗?
  • @Barmar 这是对早期版本问题的回答。这应该被编辑或删除,现在问题更清楚了。
  • 即使原始版本在标题中问“我怎么能...”,它也不仅仅是问伪代码是否可以工作。
  • @Barmar:无论这是否完全回答了这个问题,这都是关于为什么最初的尝试不可行的有用信息。
【解决方案2】:

所有浮点类型都具有相同的大小,因此您的方法将不起作用。您可以使用ceilf检查浮点数是否为整数

float num = 1.5; 
if (ceilf(num) == num)
  printf ("INTEGER");
else
  printf("FLOAT");

【讨论】:

  • 谢谢!这是一个很好的技巧。
  • @Vandervidi 这不是检查整数或比较浮点数的可靠方法,除非在非常琐碎和可预测的情况下。请参阅article,我在my answer 中有详细信息。
  • @JasonC:这个答案完全符合问题的要求;它确定浮点值是否表示整数。所以它是完全可靠的。
  • @OliCharlesworth 实际上没有。 powf(powf(3.0f,0.05f),20.0f) 不代表整数吗?在数学上, (3^(1/20))^20 是一个整数,其目的是执行该计算 - 预期会得到一个表示整数的结果。然而,这个答案声称它不是整数。众所周知,盲 == 对于比较浮点值并不稳健,舍入误差是一个需要处理的问题。与整数相比,浮点值必须更加小心。这个问题也存在于更多的人中,而不仅仅是 OP。
  • @JasonC:浮点计算不能给出数学上理想的结果是一个单独的问题,恕我直言。毫无疑问,想要确定 num 是否代表一个精确的整数值是有正当理由的。
【解决方案3】:

你可以使用modff():

const char * foo (float num) {
    float x;
    modff(num, &x);
    return (num == x) ? "INTEGER" : "FLOAT";
}

modff() 将采用float 参数,并将其分解为整数和小数部分。它将整数部分存储在第二个参数中,并返回小数部分。

【讨论】:

  • 如果由于来自任何计算 num 的舍入错误,数字与整数略有不同,则此操作失败。
  • @Jason C IMO:与整数略有不同的数字不是整数。提供给这种检测功能的参数应该被认为是准确的。这是 math.h 函数的质量评估 - 提供的答案基于输入准确的假设。可以按照您的建议制作一个 2 参数函数 foo2(x, range_factor) 来做更多事情。
  • @JasonC:如果你想思考一个更有趣的例子,请考虑the same floating point number will round to two different values的情况。
  • @Jason C puts(foo(powf(powf(3,1/20),20))); --> "整数\n"。当然,您的编译将返回相同的结果。 puts(foo(powf(powf(3,1.0/20),20))); 可能会打印“FLOAT\n”,因为典型的double 确实在做更接近powf(powf(3,0.05000000000000000278),20) 的事情,并且不应该产生整数。 pow() 调用混淆了二进制 FP 的 1.0/20 不精确性——问题的核心。
  • @Jason CA 调用来确定double 的“整数”只是对modf()ceil() 等的调用。确定near的测试> double 的“整数”要复杂得多,需要一个额外的参数来衡量“接近度”。接近度(相对的、绝对的或其他的)对于定义来说是非常重要的,并且对于通用解决方案来说很少令人满意,而且 IMO 肯定远远超出了 OP 的要求。您关于 FP 数学不精确的观点很重要,但在这篇文章的结尾。
【解决方案4】:

“简单”的方式,但有一个问题:

可以使用roundf,像这样:

float z = 1.0f;

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

这种技术和其他类似技术(例如ceilf)的问题在于,虽然它们对整数常量很有效,但如果数字是受浮点舍入计算的结果,它们就会失败-关闭错误。例如:

float z = powf(powf(3.0f, 0.05f), 20.0f);

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

打印“分数”,即使 (31/20)20 应该等于 3,因为实际计算结果最终是 2.9999992847442626953125.

那么我们该如何处理呢?

任何类似的方法,无论是fmodf 还是其他,都受制于此。在执行复杂或容易舍入计算的应用程序中,通常您想要做的是为构成“整数”的内容定义一些“容差”值(这通常适用于浮点相等比较)。我们经常将这种容差称为epsilon。例如,假设我们会原谅计算机最多 +/- 0.00001 的舍入误差。然后,如果我们正在测试z,我们可以选择 0.00001 的 epsilon 并执行以下操作:

if (fabsf(roundf(z) - z) <= 0.00001f) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

你真的不想在这里使用ceilf,因为例如ceilf(1.0000001) 是 2 而不是 1,ceilf(-1.99999999) 是 -1 而不是 -2。

选择适合您应用的公差值。欲了解更多信息,请查看comparing floating-point numbers 上的这篇文章。

【讨论】:

  • 这确实取决于应用程序。如果他只关心浮点数是否没有小数部分,那么使用 epsilon 技巧将产生错误的答案(即 1.0000001 应该是浮点数)
  • @jh314 是的,应该始终根据应用程序选择 epsilon,并且“0”可能对某些应用程序有效。但是,将此信息放在答案中很重要。虽然 OP 可能不在乎,但这个问题肯定会出现在“检查浮点数是否为整数”的搜索结果顶部附近,并且完整性有助于世界减少错误/错误信息。
猜你喜欢
  • 1970-01-01
  • 2023-03-14
  • 2013-11-29
  • 2013-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
相关资源
最近更新 更多