C Is运算符≤;用于浮点比较的UB?

C Is运算符≤;用于浮点比较的UB?,c,floating-point,precision,C,Floating Point,Precision,关于这个主题(或)有许多参考文献。但是,我仍然无法理解为什么我最喜欢的编译器(insert clang和/或gcc)没有将以下内容视为UB并正确报告,并给出一个简洁的警告: // f1, f2 and epsilon are defined as double if ( f1 / f2 <= epsilon ) 或 double res=f1/f2; 如果(res我想你是这样的。C语言不强制要求IEEE 754,所以所有浮点运算本质上都是实现定义的。但这与未定义的行为不同。唯一会出现未定

关于这个主题(或)有许多参考文献。但是,我仍然无法理解为什么我最喜欢的编译器(insert clang和/或gcc)没有将以下内容视为UB并正确报告,并给出一个简洁的警告:

// f1, f2 and epsilon are defined as double
if ( f1 / f2 <= epsilon )

double res=f1/f2;

如果(res
我想你是这样的。C语言不强制要求IEEE 754,所以所有浮点运算本质上都是实现定义的。但这与未定义的行为不同。

唯一会出现未定义行为的情况是,当一个大的浮点变量降级为一个不能表示t的较小的浮点变量时他很满意。我不太明白这在这种情况下是怎么回事

您引用的文本关注浮点数是否可以计算为双精度浮点数等,正如您不幸未包含在报价中的文本所示:

评估格式的使用具有以下特点: FLT_EVAL_方法的实施定义值:

-1不确定

0仅根据类型的范围和精度评估所有操作和常数

1将浮点型和双精度型的运算和常数评估为双精度型的范围和精度,将长双精度型的运算和常数评估为长双精度型的范围和精度

2根据长双精度类型的范围和精度评估所有操作和常数

但是,我不认为此宏会覆盖通常算术转换的行为。通常的算术转换保证您永远无法比较两个大小不同的浮点变量。因此,我不认为您在这里会遇到未定义的行为。唯一可能的问题是性能

理论上,如果
FLT\u EVAL\u METHOD==2
,那么您的操作数确实可以被计算为类型
long double
。但是请注意,如果编译器允许将此类隐式升级到更大的类型,这是有原因的

根据您引用的文本,显式强制转换将对抗这种编译器行为


在这种情况下,如果((双重)(f1/f2)经过一段时间的聊天,代码
if((双重)(f1/f2),那么就可以清楚地知道错误通信的来源

标准中引用的部分明确允许实现在计算中对浮点操作数使用更广泛的格式。这包括,但不限于,对
操作数使用
长双
格式

有关的标准部分也没有称之为“类型提升”。它只是指正在使用的格式

因此,
f1/f2
可以在一些任意的内部格式中执行,但不会使结果成为除
double
之外的任何其他类型


所以当比较结果时(通过
我不理解你的问题。你引用的标准部分实际上说,到
double
的升级将在评估期间自动完成,因此不需要显式转换。为什么,为什么,为什么会是未定义的行为?我在你的标准引用中没有看到任何表明这一点的内容。在你链接到的问题。是的,它有时会产生反直觉的结果。但这与UB有什么关系?结果定义得很好,只是偶尔与天真的期望不符。@尼伯兹你已经反向阅读了。
f1/f2
至少是双精度的,而不是相反。请重新措辞并发布一个新问题,从你的两个假设中退一步,而不是询问你从这些假设中得出的结论,而是质疑假设本身。这应该是清楚的(从这里冗长的讨论和接近的投票)人们很难弄清楚你到底在问什么。@DevSolar我没有改变一点最初的问题。我已经解释了一些中间步骤,这些步骤对我来说似乎很明显,但这里的一些管理员显然没有。我的疑问仍然是一样的。谢谢你的帮助。那么你说的是
epsilon
(64位)以80位精度复制到FPU,例如,在执行相等之前?标准上说“可能是”。这意味着“可能不是”但是为什么这很重要,你在哪里可以看到UB?@ DeEng:经常被认为是不好的。只要你知道你在做什么,比较浮动是完全可以接受的。例如,在2位IEEE75 4中,整数可以被精确地比较为53 ^ 53。@ Bathsheba:但是编译器警告OP指的是不关心这一点,他们认为AL。l
=
应用于浮点数“bad”。但是——这是针对OP的——“生成警告”并不等同于“is UB”。@malat:为什么“计算的格式的范围和精度[可能]大于类型要求的格式?”--比如,将内存中的64位
f1
f2
,和/或
epsilon
放入80位FPU寄存器会导致截断?你在这里没有意义。感谢你给出了非常清晰的答案!
if ( (double)(f1 / f2) <= epsilon )
double res = f1 / f2;
if ( res <= epsilon )
if ( f1 / f2 < epsilon )
if ( (double)((double)f1 / (double)f2) <= epsilon )
double div = (double)f1 / (double)f2;
if( (double)div <= (double)epsilon )