我有一个“x”值数组(PDE求解器的网格),当我传递给基于这些x值填充另一个数组的函数时,涉及一个x值的特定表达式无法正确评估。 x值范围是-1:1,增量为0.0125,并且在x = -0.5,并且在x = 0.5时,我需要以不同于其他值的方式处理这些情况。但是,对于x = 0.5的点,下面的块无法评估为TRUE(对于x = -0.5,它是可以的)。这是问题块的精简片段,详情如下:
int N = 160;
double delta_x = 0.0125;
const double lims = 0.5 * delta_x;
for(int i = 0; i <= N; i++)
{
if((x[i] < -0.5) || (x[i] > 0.5)) sol[i] = 0;
else if( (abs(x[i] + 0.5) < lims) || (abs(x[i] - 0.5) < lims) ) sol[i] = 0.5;
else sol[i] = 1;
cout << setprecision(30) << "lims: " << lims << ", abs(x[i] - 0.5): " << abs(x[i] - 0.5) << endl;
cout << "sol[" << i << "]: " << sol[i] << endl;
}
这是x = 0.5的输出:
lims: 0.00625000000000000034694469519536, abs(x[i] - 0.5): 1.11022302462515654042363166809e-16
sol[120]: 0
因此,看起来if语句中的表达式应该在x = 0.5时返回TRUE,即使它当然不是0.5,因为它在范围的“lims”范围内。有什么想法??
答案 0 :(得分:3)
回答原始问题
if
语句中的表达式确实评估为真。如果没有,那么你就不会看到你在问题中包含的输出。
FWIW,更简单的测试将是
abs(abs(x[i]) - 0.5) < lims
回答最新版本的问题
if((x[i] < -0.5) || (x[i] > 0.5)) sol[i] = 0;
else if( (abs(x[i] + 0.5) < lims) || (abs(x[i] - 0.5) < lims) ) sol[i] = 0.5;
else sol[i] = 1;
您声明x[i]
接近0.5,但未将sol[i]
设置为0.5,实际上将其设置为0
。在这种情况下,唯一合理的结论是x[i] > 0.5
并满足第一个条件:
if((x[i] < -0.5) || (x[i] > 0.5)) sol[i] = 0;
所以你需要改变测试的顺序:
if( (abs(x[i] + 0.5) < lims) || (abs(x[i] - 0.5) < lims) ) sol[i] = 0.5;
else if((x[i] < -0.5) || (x[i] > 0.5)) sol[i] = 0;
else sol[i] = 1;
我会这样写:
if (abs(abs(x[i]) - 0.5) < lims)
sol[i] = 0.5;
else if ((x[i] < -0.5) || (x[i] > 0.5))
sol[i] = 0;
else
sol[i] = 1;
请将来确保在您提出的问题中包含正确的代码。
答案 1 :(得分:1)
好吧,现在在您更正代码之后,问题显而易见。对于x[i] = 0.5
,控件被第一个条件
if((x[i] < -0.5) || (x[i] > 0.5)) sol[i] = 0;
它甚至没有进行abs
评估。
浮点数并不总是精确的。虽然0.5
确实可以精确表示,但它仅适用于直接分配0.5
或使用一些简单且特别稳定的评估来达到该值的情况(例如{{1} }})。在更复杂的情况下,您最终可能会得到不精确的1.0/2
值(如0.5
的情况)。这就是导致它被第一个0.1 * 5
拦截的原因。您的积极if
不精确,恰好大于精确的0.5
。
解决问题的一种方法可能是先进行基于0.5
的近似比较,然后进行“精确”比较
lim