0

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

Sample code:

#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
4

3 回答 3

1

这可能不是您正在寻找的答案,而且它可能看起来很滑稽,但在我自己的工作中,我几乎可以想象我有这个宏可供我使用。float它具有在、doublelong 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)or if(f == 1)or的比较if(f == 3)在实践中非常好。我会毫不犹豫地将浮点变量与小于 10 的整数进行比较,或者小于 100,如果是这样的话,也可能是 0.5。但是对于我可能想到的任何其他数字,或者我可能在 C 程序中的浮点变量中进行操作,它完全可以表示为 a floator的可能性double几乎微乎其微。

于 2021-08-18T16:13:45.853 回答
1

如何确定可以表示给定浮动常量的无转换?

就 C 语义而言,编译器接受的浮动常量具有类型float,或某些扩展浮动类型。它代表了。doublelong double

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

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

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

于 2021-08-18T17:44:54.463 回答
1

“无转换”似乎是不必要的限制性要求,但可以让 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 常量的小数部分不以5or结尾0,则它不能完全转换为 a float/double

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

于 2021-08-18T20:31:30.923 回答