Мне нужна линейная интерполяция в 2D-массиве. Вывод в Codeblocks правильный, а в VisualStudio — нет.
У меня есть 2 основные функции.
Линейная интерполяция в 1D-массиве: Функция — Y(X), а результат — Y(x).
Линейная интерполяция в 2D-массиве: Функция — Y(X1, X2), а результат — Y(x, y).
И функция, чтобы проверить это.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
double lin_int(int size, double* X, const double* Y, double x){
int i;
if (x >= *(X + size-1)){
return *(Y + size-1);
} else
if (x <= *(X)){
return *(Y);
}
for(i = 1; i < size; i++){
if (*(X + i) >= x && *(X + i - 1) <= x){
if (*(X+i) == *(X+i-1)){
return *(Y + i - 1)+(*(Y + i)-*(Y + i - 1))*(x-*(X+i-1))/(*(X+i-1)*2); //два совпадающих значения в узлах (деление на ноль)
}
return *(Y + i - 1)+(*(Y + i)-*(Y + i - 1))*(x-*(X+i-1))/(*(X+i)-*(X+i-1));
}
}
}
/*
| X2[j] y X2[j+1]
_____________|_____________________________________________________________
X1[i] | Y[i][j] x1 Y[i][j+1]
|
x | return
|
X1[i+1] | Y[i+1][j] x2 Y[i+1][j+1]
|
X1[m]
X2[n]
Y[m][n]
*/
double lin_int_for_mass(int m, int n, double* X1, double* X2, const double* Y, double x, double y){
int i;
int j;
double x1, x2;
bool in_X1, in_X2; //Проверки, что искомая точка за границей:
if (x < *(X1) && y < *(X2)) return *Y; //по X1 и X2 меньше оба значения x, y - возвращаем Y[0][0]
if (x > *(X1+m) && y > *(X2+n)) return *(Y+m*n-1); //по X1 и X2 больше оба значения x, y - возвращаем Y[m][n]
if (x < *(X1)) x = *(X1); //по X1 значение x меньше X1[0] - ставим x = X1[0]
if (y < *(X2)) y = *(X2); //по X2 значение y меньше X2[0] - ставим y = X2[0]
if (x > *(X1+m-1)) x = *(X1+m-1); //по X1 значение x больше X1[m] - ставим x = X1[m]
if (y > *(X2+n-1)) y = *(X2+n-1); //по X2 значение y больше X2[n] - ставим y = X2[n]
for (i = 0; i < n-1; i++){
if (x == *(X1 + i)){ //Проверка что мы в узле X1
in_X1 = true;
break;
} else
if (x > *(X1 + i) && x < *(X1 + i + 1)) break; //Если не в узле, фиксируем индекс предыдущего узла
}
for (j = 0; j < m-1; j++){
if (y == *(X2 + j)){ //Проверка что мы в узле X2
in_X2 = true;
break;
} else
if (y > *(X2 + j) && y < *(X2 + j + 1)) break; //Если не в узле, фиксируем индекс предыдущего узла
}
if (in_X1 && in_X2) { //Если попали в два узла сетки, возвращаем уже известное значение
return *((Y + i*n) + j);
} else
if (in_X1) { //Если в узле только по X1, возвращаем lin_int между узлами X2
return lin_int(n, X2, (Y+i*n), y);
} else
if (in_X2) { //Если в узле только по X2, возвращаем lin_int между узлами X1
x1 = *((Y+i*n)+j);
x2 = *((Y+(i+1)*n)+j);
if (*(X1+i+1) == *(X1+i)){
return x1 + (x2-x1) * (x-*(X1+i)) / (*(X1+i)*2); //два совпадающих значения в узлах
}
return x1 + (x2-x1) * (x-*(X1+i)) / (*(X1+i+1) - *(X1+i));
} else { //Если ни в какой узел не попали
if (*(X1+i+1) == *(X1+i)){
return x1 + (x2-x1) * (x-*(X1+i)) / (*(X1+i)*2); //два совпадающих значения в узлах
}
x1 = lin_int(n, X2, (Y+i*n), y); //Если не попали ни в какой узел, вычисляем x1, x2 и возвращаем lin_int между ними
x2 = lin_int(n, X2, (Y+(i+1)*n), y);
return x1 + (x2-x1) * (x-*(X1+i)) / (*(X1+i+1) - *(X1+i));
}
}
void test_lin_int_mass(void){
double X1[4] = { 0.3, 1.0, 4.0, 10.0 };
double X2[3] = { 0.0, 90.0, 180.0 };
double Y[4][3] =
{/* 0 90 180 */
/*0.3*/ {1.0, -0.107, -0.5},
/*1.0*/ {1.3, -0.3, -0.7},
/*4.0*/ {1.5, -0.2, -0.6},
/*10.*/ {1.53, -0.253, -0.5}
};
double i,j;
for (i=0; i<=200; i+=15){
printf("\t%.3lf", i);
}
printf("\n");
for (i=0; i<=12; i+=1){
printf("%.3lf", i);
for(j=0; j<=200; j+=15){
printf("\t%.3lf", lin_int_for_mass(4, 3, X1, X2, &Y[0][0], i, j));
}
printf("\n");
}
}
int main()
{
test_lin_int_mass();
return 0;
}
В чем причина разных результатов?
Неправильный вывод (в VisualStudio):
0.000 15.000 30.000 45.000 60.000 75.000 90.000 105.000 120.000 135.000 150.000 165.000 180.000 195.000
0.000 1.000 1.000 1.000 1.000 1.000 1.000 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
1.000 1.300 1.300 1.300 1.300 1.300 1.300 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
2.000 1.300 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
3.000 1.300 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
4.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
5.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
6.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
7.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
8.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
9.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
10.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
11.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
12.000 1.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500 -0.500
Правый вывод (в кодовых блоках):
0.000 15.000 30.000 45.000 60.000 75.000 90.000 105.000 120.000 135.000 150.000 165.000 180.000 195.000
0.000 1.000 0.816 0.631 0.447 0.262 0.077 -0.107 -0.172 -0.238 -0.304 -0.369 -0.434 -0.500 -0.500
1.000 1.300 1.033 0.767 0.500 0.233 -0.033 -0.300 -0.367 -0.433 -0.500 -0.567 -0.633 -0.700 -0.700
2.000 1.367 1.094 0.822 0.550 0.278 0.006 -0.267 -0.333 -0.400 -0.467 -0.533 -0.600 -0.667 -0.667
3.000 1.433 1.156 0.878 0.600 0.322 0.044 -0.233 -0.300 -0.367 -0.433 -0.500 -0.567 -0.633 -0.633
4.000 1.500 1.217 0.933 0.650 0.367 0.083 -0.200 -0.267 -0.333 -0.400 -0.467 -0.533 -0.600 -0.600
5.000 1.505 1.219 0.934 0.648 0.362 0.077 -0.209 -0.271 -0.334 -0.396 -0.458 -0.521 -0.583 -0.583
6.000 1.510 1.222 0.934 0.646 0.358 0.070 -0.218 -0.276 -0.334 -0.392 -0.450 -0.508 -0.567 -0.567
7.000 1.515 1.225 0.935 0.644 0.354 0.064 -0.227 -0.280 -0.334 -0.388 -0.442 -0.496 -0.550 -0.550
8.000 1.520 1.227 0.935 0.642 0.350 0.057 -0.235 -0.285 -0.335 -0.384 -0.434 -0.484 -0.533 -0.533
9.000 1.525 1.230 0.935 0.640 0.346 0.051 -0.244 -0.290 -0.335 -0.380 -0.426 -0.471 -0.517 -0.517
10.000 1.530 1.233 0.936 0.639 0.341 0.044 -0.253 -0.294 -0.335 -0.377 -0.418 -0.459 -0.500 -0.500
11.000 1.530 1.233 0.936 0.639 0.341 0.044 -0.253 -0.294 -0.335 -0.377 -0.418 -0.459 -0.500 -0.500
12.000 1.530 1.233 0.936 0.639 0.341 0.044 -0.253 -0.294 -0.335 -0.377 -0.418 -0.459 -0.500 -0.500
В вашем коде слишком много однобуквенных переменных, сложно понять, что они обозначают.
@Харит, я написал, какая переменная за что отвечает, надеюсь, ты это понимаешь. Я также добавил комментарии для представления структуры массивов.
какой вывод правильный, а какой неправильный? и чем они отличаются?
Добавил богболт для образца godbolt.org/z/7af9W4Mnr
@JohannGerell только что добавил дезинфицирующее средство и обнаружил ошибку, godbolt.org/z/M38hsE4rM
Пожалуйста, включите предупреждения компилятора: 'lin_int': не все пути управления возвращают значение. Если других путей действительно нет, то не запутывайте код ненужными операторами else.
Будьте осторожны при сравнении значений с плавающей запятой на предмет равенства.
Добавлены правильные и неправильные выводы.





Функция lin_int_for_mass() имеет неопределенное поведение как минимум в двух местах:
x1 и x2 на каждом пути через эту функцию; в частности, если ни in_X1, ни in_X2 не являются истинными, вы можете нажать оператор возврата в строке 77, даже не инициализируя их.in_X1 и in_X2; у вас есть UB, если только оба x == *(X1 + i) для любых x, X1 и i и y == *(X2 + j) для любых y, X2 и j.Эта проблема может возникнуть и в других местах вашего кода; Как правило, избегайте объявления переменной без ее инициализации. Если вы не используете древний языковой стандарт, вам не нужно объявлять переменные поверх функции, а затем назначать их позже (что вы можете забыть сделать); вы можете объявить и инициализировать их прямо там, где они вам нужны.
Основная проблема была в функции lin_int_for_mass. Я не инициализировал in_X1 и in_X2 как false по умолчанию.
Каждый раз, когда я читаю «Здесь другое поведение, чем там…», я думаю о «Неопределенном поведении». Знаете ли вы об этом? В любом случае, пожалуйста, предоставьте минимально воспроизводимый пример, в идеале с жестко запрограммированным вводом, который демонстрирует то, что вы наблюдаете, желательно сопровождаемый заявлением о том, что вы действительно используете его одинаково в обеих средах. Приятно иметь: комментарии на английском языке.