У меня есть массив значений «x» (сетка для решателя PDE), что когда я передаю функцию, которая заполняет другой массив на основе этих значений x, определенное выражение, включающее одно значение x, не оценивается должным образом. Диапазон значений х равен -1: 1 с шагом 0,0125, а при х = -0,5 и при х = 0,5 мне нужно обрабатывать эти случаи иначе, чем другие значения. Однако приведенный ниже блок не может быть оценен как ИСТИНА для точки х = 0,5 (это нормально для х = -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;
}
Вот вывод для х = 0,5:
lims: 0.00625000000000000034694469519536, abs(x[i] - 0.5): 1.11022302462515654042363166809e-16
sol[120]: 0
Таким образом, похоже, что выражение в операторе if должно возвращать TRUE, когда x = 0,5, хотя, конечно, это не точно 0,5, поскольку оно находится в пределах «лимита» диапазона. Какие-нибудь мысли??
Ответ на оригинальный вопрос
Выражение в 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;
Пожалуйста, в будущем обязательно укажите правильный код в вопросе, который вы задаете.
Что ж, теперь, после того как вы исправили свой код, проблема очевидна. За 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;