tru*_*kar 3 c floating-point gcc compiler-optimization
在使用自动CI测试时,我发现了一些代码,如果将gcc的优化设置为-O2则会破坏代码。如果双精度值在任一方向都超过阈值,则代码应增加一个计数器。
转到-O1或使用-ffloat-store选项可解决此问题。
这是一个显示相同问题的小例子。update()每当序列的*pNextState * 1e-6阈值超过0.03 时,该函数应返回true 。我使用按引用调用,因为这些值是完整代码中大型结构的一部分。
使用<和背后的想法>=是,如果一个序列恰好击中了该值,则函数这次应返回1,而在下一个周期返回0。
test.h:
extern int update(double * pState, double * pNextState);
Run Code Online (Sandbox Code Playgroud)
test.c:
#include "test.h"
int update(double * pState, double * pNextState_scaled) {
static double threshold = 0.03;
double oldState = *pState;
*pState = *pNextState_scaled * 1e-6;
return oldState < threshold && *pState >= threshold;
}
Run Code Online (Sandbox Code Playgroud)
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
int main(void) {
double state = 0.01;
double nextState1 = 20000.0;
double nextState2 = 30000.0;
double nextState3 = 40000.0;
printf("%d\n", update(&state, &nextState1));
printf("%d\n", update(&state, &nextState2));
printf("%d\n", update(&state, &nextState3));
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
将gcc至少与-O2一起使用,输出为:
0
0
0
Run Code Online (Sandbox Code Playgroud)
将gcc与-O1,-O0或-ffloat-store一起使用可产生所需的输出
0
1
0
Run Code Online (Sandbox Code Playgroud)
据我了解,调试产生的问题是,如果编译器优化了堆栈上的局部变量oldstate,而是与具有较高精度(80位)的浮点寄存器中的中间结果进行比较,并且该值*pState比阈值小一点。如果用于比较的值以64位精度存储,则逻辑不会错过阈值。由于乘以1e-6,结果可能存储在浮点寄存器中。
您会认为这是gcc错误吗?lang不显示问题。
我在Intel Core i5,Windows和msys2上使用gcc版本9.2.0。
我很清楚浮点数比较不准确,我认为以下结果有效:
0
0
1
Run Code Online (Sandbox Code Playgroud)
这个想法是,如果(*pState >= threshold) == false在一个周期内,那么oldstate = *pState在后续调用中将相同的值()与相同的阈值进行比较(*pState < threshold)就必须为真。
[免责声明:这是一个通用的,从船上射击的答案。浮点问题可能很微妙,我没有仔细分析这一问题。有时,像这样可疑的代码可以最终使之可移植且可靠地工作,并且按照公认的答案,似乎就是这种情况。尽管如此,通用答案仍然是一般情况。]
我会认为这是测试用例中的错误,而不是gcc中的错误。这听起来像是经典的代码示例,相对于精确的浮点数相等,它不必要地脆弱。
我建议:
我不建议:
| 归档时间: |
|
| 查看次数: |
96 次 |
| 最近记录: |