为何循环中变量值出现偏差?浮点精度与数组计算问题排查
浮点数精度偏差与数组越界问题分析
问题场景
这段C代码用于计算7个浮点项(仅展示tpos1和tpos2的计算逻辑),并从中筛选最小的正非零项。
核心计算代码
int hitb; double PCLx = 2.936728; double PCLz = -0.016691; double PDCx = 0.102796; double PDCz = 0.994702; double q = 0.002344; double s = 0.0266; double v = 0.0744; double a = -q * PDCx * PDCx; double b = s * PDCx - 2 * q*PCLx*PDCx - PDCz; double c = -1.0*(PCLz + q * pow(PCLx, 2) - s * PCLx + v); double d = b * b - 4 * a*c; if (d >= 0.0f) // 仅保留实数解 { tpos1 = (-b + sqrt(d)) / (2 * a); tpos2 = (-b - sqrt(d)) / (2 * a); } printf("\n %f %f %f %f %f %f %f", tcapneg, tcappos, tneg1, tneg2, tpos1, tpos2, tzcap);
运行输出
0.000000 0.000000 -40326.381162 -0.156221 -40105.748386 0.000194 0.016780
预期最小正非零项为tpos2=0.000194,但执行筛选循环后:
double smallest = -1.0; double tlist[7] = { tcapneg, tcappos, tneg1, tneg2, tpos1, tpos2, tzcap }; const int size = sizeof(tlist) / sizeof(int); for (int i = 0; i < size; i++) { if (tlist[i] > EPSILON && (smallest == -1.0 || tlist[i] < smallest)) { smallest = tlist[i]; } } printf("\n %f", smallest);
输出的smallest值为0.000192,与tpos2的显示值不符,导致后续hitb赋值逻辑失败。
问题原因
数组长度计算错误
代码中const int size = sizeof(tlist) / sizeof(int);是致命错误:tlist是double类型数组,sizeof(tlist)为7*8=56字节,sizeof(int)为4字节,计算后size=14,远大于实际的7个元素。循环会越界访问数组后的内存垃圾值,这些垃圾值可能是一个接近0.000192的正数,被错误选为最小值。浮点数打印与实际存储的差异
%f格式默认只保留6位小数,double类型实际存储的是更高精度的二进制浮点值。tpos2的真实值可能是0.000193xxxx,打印时四舍五入为0.000194,但参与比较的是未四舍五入的原始值;而筛选后打印的0.000192同样是垃圾值的四舍五入结果,并非tpos2本身。
修复方案
- 修正数组长度计算:将
sizeof(int)改为sizeof(double),或直接用sizeof(tlist[0]),即const int size = sizeof(tlist) / sizeof(tlist[0]);,确保循环仅遍历7个有效元素。 - 精确查看浮点数:用
%.10f等更高精度的格式打印,避免因四舍五入造成的视觉误解;浮点数比较时避免直接使用==,改用基于EPSILON的范围判断。
内容的提问来源于stack exchange,提问作者iontrap
相关产品推荐
相关产品推荐

