如果语句在应该的时候没有评估为TRUE

时间:2013-11-08 22:28:16

标签: c++ numerical-methods numerical-analysis

我有一个“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”范围内。有什么想法??

2 个答案:

答案 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