如何确定给定的浮点常量可以表示的 w/o 次转换?

How to determine w/o conversions that a given floating constant can be represented?

如何确定给定浮点常量可以表示的 w/o 次转换?

示例代码:

#define FLOATING_CONSTANT1  2147483647.0f
#define FLOATING_CONSTANT2  2147483520.0f

bool b1 = FLOATING_CONSTANT_CAN_BE_REPRESENTED( FLOATING_CONSTANT1 );  // false
bool b2 = FLOATING_CONSTANT_CAN_BE_REPRESENTED( FLOATING_CONSTANT2 );  // true

这可能不是您正在寻找的答案,而且它可能看起来很滑稽,但在我自己的工作中,我几乎可以想象我可以使用这个宏。它具有在 floatdoublelong double 操作数上同样出色地工作的便利优势:

#define fp_is_exact(f) 0

但我承认我很少写像

这样的东西
if(fp_is_exact(x))
    do something the easy way;
else
    do something the hard way;

我将不得不编写代码来以困难的方式完成它,无论如何,“简单”的代码很少被使用,所以我不妨改掉想象它可能永远的习惯对任何事情都有用。

严肃地说:假设浮点数永远不会精确而言,精确性并非如此。无论如何,您可能需要表示为浮点变量的任何东西都不是确切已知的量,尤其是如果它是您在现实世界中测量的东西,例如距离、重量或速度或其他东西。 (我最喜欢的例子:从洛杉矶到纽约有多远?以英寸为单位?)


附录:我不得不承认,我不得不承认,有时假设浮点数是精确的是合适的。 if(f == 0)if(f == 1)if(f == 3) 这样的比较在实践中完全没问题。我会毫不犹豫地将一个浮点变量与一个小于 10 或小于 100(如果是 0.5)的整数进行完全相等的比较。但是对于我可能想到的几乎任何其他数字,或者我可能在 C 程序中操作浮点变量,它完全可以表示为 floatdouble 的可能性是几乎消失得无影无踪。

How to determine w/o conversions that a given floating constant can be represented?

编译器接受的浮动常量具有类型 floatdoublelong double 或就 C 语义而言的某种扩展浮动类型。它表示的。

但我想问题是源代码中出现的常量的十进制词汇表达式是否对应于完全可表示的某些选定浮点数的浮点值类型。我非常有信心地说预处理器无法做出这样的决定,因为预处理器以(预处理器)令牌为单位进行交易。尽管在某些情况下它通过将文本转换为数字来运行,但预处理器没有可访问的机制来将标记分解成更小的部分。

但是,可以在编译时对感兴趣的标记进行字符串化,并在 运行 时分析生成的字符串表示形式。原则上也可以编写独立工具或改编现有的独立预处理器来执行您想要的测试类型。

甚至可以想象编译器可能会提供一个选项来警告无法准确表示的词法浮点数,another question 中考虑了该替代方案。 (剧透:这不是编译器作者历来认为值得实施的替代方案。)

“w/o 转换”似乎是一个不必要的限制性要求,但可以让 OP 开始并为其他人提供测试工具。


#define str(s) #s
#define xstr(s) str(s)
#define FLOATING_CONSTANT_CAN_BE_REPRESENTED(fc1) float_const_test(xstr(fc1), fc1)

bool float_const_test(const char *s, float f1) {
  printf("<%s> %g\n", s, f1);
  char *endptr;
  errno = 0;
  double d2 = strtod(s, &endptr);
  if (s == endptr) return false;
  if (strcmp(endptr, "f") && strcmp(endptr, "F")) return false;
  if (f1 != d2) return false;
  // Note a 100% here, the string may have rounded to a double.
  return true;
}

int main(void) {
  puts("Good");
  printf("%d\n", FLOATING_CONSTANT_CAN_BE_REPRESENTED(1.5f));
  printf("%d\n", FLOATING_CONSTANT_CAN_BE_REPRESENTED(0x1.5p0f));
  puts("\nBad");
  printf("%d\n", FLOATING_CONSTANT_CAN_BE_REPRESENTED(1.23f));
  printf("%d\n", FLOATING_CONSTANT_CAN_BE_REPRESENTED(1.23e40f));
}

输出

Good
<1.5f> 1.5
1
<0x1.5p0f> 1.3125
1

Bad
<1.23f> 1.23
0
<1.23e40f> inf
0

备注:

如果 FP 常量的小数部分不是以 50 结尾,则无法准确转换为 float/double

当需要exact FP常量时,第一步是考虑hexadecimal-floating-constant这样的0x1.23CDp12f