我有一个"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"内。 有什么想法吗??
对原始问题的回答
if
语句中的表达式确实计算为 true。如果没有,那么您将不会看到问题中包含的输出。
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;
将来请务必在您提出的问题中包含正确的代码。
好吧,现在在你更正代码之后,问题很明显了。对于x[i] = 0.5
控件被第一个条件截获
if((x[i] < -0.5) || (x[i] > 0.5)) sol[i] = 0;
它甚至没有达到你的abs
评估。
浮点数并不总是精确的。虽然确实可以精确表示0.5
,但它仅适用于直接分配0.5
或使用一些简单且特别稳定的计算来达到该值的情况(例如在1.0/2
的情况下)。在更复杂的情况下,您最终可能会得到不精确的0.5
值(例如在0.1 * 5
的情况下)。这就是导致它被第一个if
拦截的原因。您的正0.5
是不精确的,恰好大于精确的0.5
。
解决此问题的一种方法可能是将基于lim
的近似比较放在首位,然后进行"精确"比较
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;